Class: ActiveDocument::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/active_document/base.rb

Constant Summary collapse

@@environment =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Base

Returns a new instance of Base.



178
179
180
181
182
183
184
185
186
# File 'lib/active_document/base.rb', line 178

def initialize(attributes = {})
  if attributes.kind_of?(String)
    @attributes, @saved_attributes = Marshal.load(attributes)      
  else
    @attributes = attributes
  end
  @attributes       = HashWithIndifferentAccess.new(@attributes)       if @attributes
  @saved_attributes = HashWithIndifferentAccess.new(@saved_attributes) if @saved_attributes
end

Instance Attribute Details

#saved_attributesObject (readonly)

Returns the value of attribute saved_attributes.



188
189
190
# File 'lib/active_document/base.rb', line 188

def saved_attributes
  @saved_attributes
end

Class Method Details

._load(data) ⇒ Object



258
259
260
# File 'lib/active_document/base.rb', line 258

def self._load(data)
  new(data)
end

.accessor(*attrs) ⇒ Object



165
166
167
168
# File 'lib/active_document/base.rb', line 165

def self.accessor(*attrs)
  reader(*attrs)
  writer(*attrs)
end

.close_databaseObject



81
82
83
84
85
86
87
# File 'lib/active_document/base.rb', line 81

def self.close_database
  if @database_open
    databases.values.each {|database| database.close}
    environment.close
    @database_open = false
  end
end

.create(*args) ⇒ Object



34
35
36
37
38
# File 'lib/active_document/base.rb', line 34

def self.create(*args)
  model = new(*args)
  model.save
  model
end

.database(field = nil) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/active_document/base.rb', line 89

def self.database(field = nil)
  open_database # Make sure the database is open.
  field ||= :primary_key
  field = field.to_sym
  return if self == ActiveDocument::Base
  databases[field] ||= super
end

.database_name(database_name = nil) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/active_document/base.rb', line 10

def self.database_name(database_name = nil)
  if database_name
    raise 'cannot modify database_name after db has been initialized' if @database_name
    @database_name = database_name
  else
    return if self == ActiveDocument::Base 
    @database_name ||= name.underscore.gsub('/', '-').pluralize
  end
end

.databasesObject



67
68
69
# File 'lib/active_document/base.rb', line 67

def self.databases
  @databases ||= {}
end

.define_field_accessor(field_or_fields, field = nil) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/active_document/base.rb', line 113

def self.define_field_accessor(field_or_fields, field = nil)    
  if field_or_fields.kind_of?(Array)
    field ||= field_or_fields.join('_and_').to_sym
    define_method(field) do
      field_or_fields.collect {|f| self.send(f)}.flatten
    end
  elsif field
    define_method(field) do
      self.send(field_or_fields)
    end
  else
    field = field_or_fields.to_sym
  end
  field
end

.define_find_methods(name, opts = {}) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/active_document/base.rb', line 129

def self.define_find_methods(name, opts = {})
  field = opts[:field] || name

  (class << self; self; end).instance_eval do
    define_method("find_by_#{name}") do |*args|
      merge_opts(args, :limit => 1, :partial => opts[:partial])
      find_by(field, *args).first
    end

    define_method("find_all_by_#{name}") do |*args|
      merge_opts(args, :partial => opts[:partial])
      find_by(field, *args)
    end
  end
end

.environmentObject



21
22
23
# File 'lib/active_document/base.rb', line 21

def self.environment
  @@environment[path] ||= ActiveDocument::Environment.new(path)
end

.find(key, opts = {}) ⇒ Object



107
108
109
110
111
# File 'lib/active_document/base.rb', line 107

def self.find(key, opts = {})
  doc = database.find([key], opts).first
  raise ActiveDocument::DocumentNotFound, "Couldn't find #{name} with id #{key.inspect}" unless doc
  doc
end

.find_by(field, *keys) ⇒ Object



101
102
103
104
105
# File 'lib/active_document/base.rb', line 101

def self.find_by(field, *keys)
  opts = extract_opts(keys)
  keys << :all if keys.empty?
  database(field).find(keys, opts)
end

.index_by(field_or_fields, opts = {}) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/active_document/base.rb', line 55

def self.index_by(field_or_fields, opts = {})
  field = define_field_accessor(field_or_fields)
  raise "index on #{field} already exists" if databases[field]
  databases[field] = ActiveDocument::Database.new(opts.merge(:field => field, :model_class => self))    
  define_find_methods(field) # find_by_field1_and_field2

  # Define shortcuts for partial keys.
  if field_or_fields.kind_of?(Array) and not respond_to?(field_or_fields.first)
    define_find_methods(field_or_fields.first, :field => field, :partial => true) # find_by_field1
  end
end

.open_databaseObject



71
72
73
74
75
76
77
78
79
# File 'lib/active_document/base.rb', line 71

def self.open_database
  unless @database_open
    environment.open
    databases[:primary_key].open # Must be opened first for associate to work.
    databases.values.each {|database| database.open}
    @database_open = true
    at_exit { close_database }
  end
end

.path(path = nil) ⇒ Object



2
3
4
5
6
7
8
# File 'lib/active_document/base.rb', line 2

def self.path(path = nil)
  if path
    @path = path
  else
    @path ||= (self == ActiveDocument::Base ? ActiveDocument::DEFAULT_PATH : ActiveDocument::Base.path)
  end
end

.primary_key(field_or_fields) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/active_document/base.rb', line 40

def self.primary_key(field_or_fields)    
  databases[:primary_key] = ActiveDocument::Database.new(:model_class => self, :unique => true)

  field = define_field_accessor(field_or_fields)
  define_find_methods(field, :field => :primary_key) # find_by_field1_and_field2
  
  define_field_accessor(field_or_fields, :primary_key)
  define_find_methods(:primary_key) # find_by_primary_key

  # Define shortcuts for partial keys.
  if field_or_fields.kind_of?(Array) and not respond_to?(field_or_fields.first)
    define_find_methods(field_or_fields.first, :field => :primary_key, :partial => true) # find_by_field1
  end
end

.reader(*attrs) ⇒ Object



149
150
151
152
153
154
155
# File 'lib/active_document/base.rb', line 149

def self.reader(*attrs)
  attrs.each do |attr|
    define_method(attr) do
      attributes[attr]
    end
  end
end

.save_method(method_name) ⇒ Object



170
171
172
173
174
175
176
# File 'lib/active_document/base.rb', line 170

def self.save_method(method_name)
  define_method("#{method_name}!") do |*args|
    value = send(method_name, *args)
    save
    value
  end
end

.timestampsObject



145
146
147
# File 'lib/active_document/base.rb', line 145

def self.timestamps
  reader(:created_at, :updated_at)
end

.transaction(&block) ⇒ Object



25
26
27
28
# File 'lib/active_document/base.rb', line 25

def self.transaction(&block)
  open_database
  environment.transaction(&block)
end

.writer(*attrs) ⇒ Object



157
158
159
160
161
162
163
# File 'lib/active_document/base.rb', line 157

def self.writer(*attrs)
  attrs.each do |attr|
    define_method("#{attr}=") do |value|
      attributes[attr] = value
    end
  end
end

Instance Method Details

#==(other) ⇒ Object



206
207
208
209
# File 'lib/active_document/base.rb', line 206

def ==(other)
  return false if other.nil?
  attributes == other.attributes
end

#_dump(ignored) ⇒ Object



252
253
254
255
256
# File 'lib/active_document/base.rb', line 252

def _dump(ignored)
  attributes       = @attributes.to_hash       if @attributes
  saved_attributes = @saved_attributes.to_hash if @saved_attributes
  Marshal.dump([attributes, saved_attributes])
end

#attributesObject



190
191
192
# File 'lib/active_document/base.rb', line 190

def attributes
  @attributes ||= Marshal.load(Marshal.dump(saved_attributes))
end

#changed?(field = nil) ⇒ Boolean

Returns:

  • (Boolean)


215
216
217
218
219
220
221
222
223
# File 'lib/active_document/base.rb', line 215

def changed?(field = nil)
  return false unless @attributes and @saved_attributes

  if field
    send(field) != saved.send(field)
  else
    attributes != saved_attributes
  end
end

#database(field = nil) ⇒ Object



97
98
99
# File 'lib/active_document/base.rb', line 97

def database(field = nil)
  self.class.database(field)
end

#destroyObject



248
249
250
# File 'lib/active_document/base.rb', line 248

def destroy
  database.delete(self)
end

#new_record?Boolean

Returns:

  • (Boolean)


211
212
213
# File 'lib/active_document/base.rb', line 211

def new_record?
  @saved_attributes.nil?
end

#saveObject



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/active_document/base.rb', line 230

def save
  attributes[:updated_at] = Time.now if respond_to?(:updated_at)
  attributes[:created_at] = Time.now if respond_to?(:created_at) and new_record?

  opts = {}
  if changed?(:primary_key)
    opts[:create] = true
    saved.destroy
  else
    opts[:create] = new_record?
  end

  @saved_attributes = attributes
  @attributes       = nil
  @saved            = nil
  database.save(self, opts)
end

#savedObject



225
226
227
228
# File 'lib/active_document/base.rb', line 225

def saved
  raise 'no saved attributes for new record' if new_record?
  @saved ||= self.class.new(saved_attributes)
end

#to_json(*fields) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/active_document/base.rb', line 194

def to_json(*fields)
  if fields.empty?
    attributes.to_json
  else
    slice = {}
    fields.each do |field|
      slice[field] = attributes[field]
    end
    slice.to_json
  end
end

#transaction(&block) ⇒ Object



30
31
32
# File 'lib/active_document/base.rb', line 30

def transaction(&block)
  self.class.transaction(&block)
end