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.



188
189
190
191
192
193
194
# File 'lib/active_document/base.rb', line 188

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

Instance Attribute Details

#saved_attributesObject (readonly)

Returns the value of attribute saved_attributes.



196
197
198
# File 'lib/active_document/base.rb', line 196

def saved_attributes
  @saved_attributes
end

Class Method Details

._load(data) ⇒ Object



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

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

.accessor(*attrs) ⇒ Object



175
176
177
178
# File 'lib/active_document/base.rb', line 175

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

.base_class(klass = self) ⇒ Object



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

def self.base_class(klass = self)
  if klass == ActiveDocument::Base or klass.superclass == ActiveDocument::Base
    klass
  else
    base_class(klass.superclass)
  end
end

.base_class?Boolean

Returns:

  • (Boolean)


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

def self.base_class?
  self == base_class
end

.close_databaseObject



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

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

.create(*args) ⇒ Object



45
46
47
48
49
# File 'lib/active_document/base.rb', line 45

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

.database(field = nil) ⇒ Object



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

def self.database(field = nil)
  open_database # Make sure the database is open.
  field ||= :primary_key
  field = field.to_sym
  database = databases[field]
  database ||= base_class.database(field) unless base_class?
  database
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 nil if self == ActiveDocument::Base
    @database_name ||= base_class? ? name.underscore.gsub('/', '-').pluralize : super
  end
end

.databasesObject



76
77
78
# File 'lib/active_document/base.rb', line 76

def self.databases
  @databases ||= { :primary_key => ActiveDocument::Database.new(:model_class => self, :unique => true) }
end

.define_field_accessor(field_or_fields, field = nil) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/active_document/base.rb', line 123

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



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/active_document/base.rb', line 139

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



33
34
35
# File 'lib/active_document/base.rb', line 33

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

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



117
118
119
120
121
# File 'lib/active_document/base.rb', line 117

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



111
112
113
114
115
# File 'lib/active_document/base.rb', line 111

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



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/active_document/base.rb', line 64

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



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

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 || (base_class? ? ActiveDocument::DEFAULT_PATH : super)
  end
end

.primary_key(field_or_fields) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/active_document/base.rb', line 51

def self.primary_key(field_or_fields)    
  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



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

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

.save_method(method_name) ⇒ Object



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

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

.timestampsObject



155
156
157
# File 'lib/active_document/base.rb', line 155

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

.transaction(&block) ⇒ Object



37
38
39
# File 'lib/active_document/base.rb', line 37

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

.writer(*attrs) ⇒ Object



167
168
169
170
171
172
173
# File 'lib/active_document/base.rb', line 167

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

Instance Method Details

#==(other) ⇒ Object



202
203
204
205
# File 'lib/active_document/base.rb', line 202

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

#_dump(ignored) ⇒ Object



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

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

#attributesObject



198
199
200
# File 'lib/active_document/base.rb', line 198

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

#changed?(field = nil) ⇒ Boolean

Returns:

  • (Boolean)


211
212
213
214
215
216
217
218
219
# File 'lib/active_document/base.rb', line 211

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



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

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

#destroyObject



244
245
246
# File 'lib/active_document/base.rb', line 244

def destroy
  database.delete(self)
end

#new_record?Boolean

Returns:

  • (Boolean)


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

def new_record?
  @saved_attributes.nil?
end

#saveObject



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/active_document/base.rb', line 226

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



221
222
223
224
# File 'lib/active_document/base.rb', line 221

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

#transaction(&block) ⇒ Object



41
42
43
# File 'lib/active_document/base.rb', line 41

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