Class: ActiveDocument::Base
- Inherits:
-
Object
- Object
- ActiveDocument::Base
- Defined in:
- lib/active_document/base.rb
Instance Attribute Summary collapse
-
#saved_attributes ⇒ Object
readonly
Returns the value of attribute saved_attributes.
Class Method Summary collapse
- ._load(data) ⇒ Object
- .accessor(*attrs) ⇒ Object
- .bool_accessor(*attrs) ⇒ Object
- .bool_reader(*attrs) ⇒ Object
- .checkpoint(opts = {}) ⇒ Object
- .close_environment ⇒ Object
- .count(field, key) ⇒ Object
- .create(*args) ⇒ Object
- .database ⇒ Object
- .database_name(database_name = nil) ⇒ Object
- .default(attr, default) ⇒ Object
- .defaults(defaults = {}) ⇒ Object
- .define_field_accessor(field_or_fields, field = nil) ⇒ Object
- .define_find_methods(name, config = {}) ⇒ Object
- .define_partial_shortcuts(fields, primary_field) ⇒ Object
- .find(key, opts = {}) ⇒ Object
- .find_by(field, *args) ⇒ Object
- .index_by(field_or_fields, opts = {}) ⇒ Object
- .partition_by ⇒ Object
- .partitions ⇒ Object
- .path(path = nil) ⇒ Object
- .path=(path) ⇒ Object
- .primary_key(field_or_fields, opts = {}) ⇒ Object
- .reader(*attrs) ⇒ Object
- .save_method(method_name) ⇒ Object
- .timestamps ⇒ Object
- .transaction(&block) ⇒ Object
- .uncloned_fields(*attrs) ⇒ Object
- .with_each_partition(&block) ⇒ Object
- .with_partition(partition, &block) ⇒ Object
- .writer(*attrs) ⇒ Object
Instance Method Summary collapse
- #==(other) ⇒ Object
- #_dump(ignored) ⇒ Object
- #attributes ⇒ Object
- #changed?(field = nil) ⇒ Boolean
- #clone(changed_attributes = {}) ⇒ Object
- #database ⇒ Object
- #delete ⇒ Object
- #deleted? ⇒ Boolean
- #destroy ⇒ Object
-
#initialize(attributes = {}, saved_attributes = nil) ⇒ Base
constructor
A new instance of Base.
- #new_record? ⇒ Boolean
- #partition ⇒ Object
- #partition_by ⇒ Object
- #read_attribute(attr) ⇒ Object
- #save(opts = {}) ⇒ Object
- #saved ⇒ Object
- #to_json(*args) ⇒ Object
- #transaction(&block) ⇒ Object
- #undelete ⇒ Object
- #update_attributes(attrs = {}) ⇒ Object
Constructor Details
#initialize(attributes = {}, saved_attributes = nil) ⇒ Base
Returns a new instance of Base.
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/active_document/base.rb', line 241 def initialize(attributes = {}, saved_attributes = nil) @attributes = HashWithIndifferentAccess.new(attributes) if attributes @saved_attributes = HashWithIndifferentAccess.new(saved_attributes) if saved_attributes # Initialize defaults if this is a new record. if @saved_attributes.nil? self.class.defaults.each do |attr, default| next if @attributes.has_key?(attr) @attributes[attr] = default.is_a?(Proc) ? default.bind(self).call : default.dup end end # Set the partition field in case we are in a with_partition block. if partition_by and partition.nil? set_method = "#{partition_by}=" self.send(set_method, database.partition) if respond_to?(set_method) end end |
Instance Attribute Details
#saved_attributes ⇒ Object (readonly)
Returns the value of attribute saved_attributes.
260 261 262 |
# File 'lib/active_document/base.rb', line 260 def saved_attributes @saved_attributes end |
Class Method Details
._load(data) ⇒ Object
375 376 377 |
# File 'lib/active_document/base.rb', line 375 def self._load(data) new(*Marshal.load(data)) end |
.accessor(*attrs) ⇒ Object
221 222 223 224 |
# File 'lib/active_document/base.rb', line 221 def self.accessor(*attrs) reader(*attrs) writer(*attrs) end |
.bool_accessor(*attrs) ⇒ Object
226 227 228 229 |
# File 'lib/active_document/base.rb', line 226 def self.bool_accessor(*attrs) bool_reader(*attrs) writer(*attrs) end |
.bool_reader(*attrs) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/active_document/base.rb', line 201 def self.bool_reader(*attrs) attrs.each do |attr| define_method(attr) do !!read_attribute(attr) end define_method("#{attr}?") do !!read_attribute(attr) end end end |
.checkpoint(opts = {}) ⇒ Object
37 38 39 |
# File 'lib/active_document/base.rb', line 37 def self.checkpoint(opts = {}) database.checkpoint(opts) end |
.close_environment ⇒ Object
110 111 112 113 |
# File 'lib/active_document/base.rb', line 110 def self.close_environment # Will close all databases in the environment. environment.close end |
.count(field, key) ⇒ Object
129 130 131 |
# File 'lib/active_document/base.rb', line 129 def self.count(field, key) database.count(field, key) end |
.create(*args) ⇒ Object
41 42 43 44 45 |
# File 'lib/active_document/base.rb', line 41 def self.create(*args) model = new(*args) model.save model end |
.database ⇒ Object
21 22 23 |
# File 'lib/active_document/base.rb', line 21 def self.database @database end |
.database_name(database_name = nil) ⇒ Object
11 12 13 14 15 16 17 18 19 |
# File 'lib/active_document/base.rb', line 11 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 |
.default(attr, default) ⇒ Object
189 190 191 |
# File 'lib/active_document/base.rb', line 189 def self.default(attr, default) defaults[attr] = default end |
.defaults(defaults = {}) ⇒ Object
184 185 186 187 |
# File 'lib/active_document/base.rb', line 184 def self.defaults(defaults = {}) @defaults ||= {} @defaults.merge!(defaults) end |
.define_field_accessor(field_or_fields, field = nil) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/active_document/base.rb', line 133 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, config = {}) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/active_document/base.rb', line 149 def self.define_find_methods(name, config = {}) field = config[:field] || name (class << self; self; end).instance_eval do define_method("find_by_#{name}") do |*args| modify_opts(args) do |opts| opts[:limit] = 1 opts[:partial] ||= config[:partial] end find_by(field, *args).first end define_method("find_all_by_#{name}") do |*args| modify_opts(args) do |opts| opts[:partial] ||= config[:partial] end find_by(field, *args) end end end |
.define_partial_shortcuts(fields, primary_field) ⇒ Object
170 171 172 173 174 175 176 177 178 |
# File 'lib/active_document/base.rb', line 170 def self.define_partial_shortcuts(fields, primary_field) return unless fields.kind_of?(Array) (fields.size - 1).times do |i| name = fields[0..i].join('_and_') next if respond_to?("find_by_#{name}") define_find_methods(name, :field => primary_field, :partial => true) end end |
.find(key, opts = {}) ⇒ Object
123 124 125 126 127 |
# File 'lib/active_document/base.rb', line 123 def self.find(key, opts = {}) doc = database.get(key, opts).first raise ActiveDocument::DocumentNotFound, "Couldn't find #{name} with id #{key.inspect}" unless doc doc end |
.find_by(field, *args) ⇒ Object
115 116 117 118 119 120 121 |
# File 'lib/active_document/base.rb', line 115 def self.find_by(field, *args) opts = extract_opts(args) opts[:field] = field args << :all if args.empty? args << opts database.get(*args) end |
.index_by(field_or_fields, opts = {}) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/active_document/base.rb', line 97 def self.index_by(field_or_fields, opts = {}) raise "cannot have a multi_key index on an aggregate key" if opts[:multi_key] and field_or_fields.kind_of?(Array) field = define_field_accessor(field_or_fields) database.index_by(field, opts) field_name = opts[:multi_key] ? field.to_s.singularize : field define_find_methods(field_name, :field => field) # find_by_field1_and_field2 # Define shortcuts for partial keys. define_partial_shortcuts(field_or_fields, field) end |
.partition_by ⇒ Object
85 86 87 |
# File 'lib/active_document/base.rb', line 85 def self.partition_by @partition_by end |
.partitions ⇒ Object
71 72 73 |
# File 'lib/active_document/base.rb', line 71 def self.partitions database.partitions end |
.path(path = nil) ⇒ Object
2 3 4 5 |
# File 'lib/active_document/base.rb', line 2 def self.path(path = nil) @path = path if path @path ||= (self == ActiveDocument::Base ? nil : ActiveDocument::Base.path) end |
.path=(path) ⇒ Object
7 8 9 |
# File 'lib/active_document/base.rb', line 7 def self.path=(path) @path = path end |
.primary_key(field_or_fields, opts = {}) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/active_document/base.rb', line 47 def self.primary_key(field_or_fields, opts = {}) raise 'primary key already defined' if @database if @partition_by = opts[:partition_by] @database = Bdb::PartitionedDatabase.new(database_name, :path => path, :partition_by => @partition_by) (class << self; self; end).instance_eval do alias_method opts[:partition_by].to_s.pluralize, :partitions alias_method "with_#{opts[:partition_by]}", :with_partition alias_method "with_each_#{opts[:partition_by]}", :with_each_partition end else @database = Bdb::Database.new(database_name, :path => path) end 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. define_partial_shortcuts(field_or_fields, :primary_key) end |
.reader(*attrs) ⇒ Object
193 194 195 196 197 198 199 |
# File 'lib/active_document/base.rb', line 193 def self.reader(*attrs) attrs.each do |attr| define_method(attr) do read_attribute(attr) end end end |
.save_method(method_name) ⇒ Object
231 232 233 234 235 236 237 238 239 |
# File 'lib/active_document/base.rb', line 231 def self.save_method(method_name) define_method("#{method_name}!") do |*args| transaction do value = send(method_name, *args) save value end end end |
.timestamps ⇒ Object
180 181 182 |
# File 'lib/active_document/base.rb', line 180 def self. reader(:created_at, :updated_at, :deleted_at) end |
.transaction(&block) ⇒ Object
29 30 31 |
# File 'lib/active_document/base.rb', line 29 def self.transaction(&block) database.transaction(&block) end |
.uncloned_fields(*attrs) ⇒ Object
319 320 321 322 323 324 325 |
# File 'lib/active_document/base.rb', line 319 def self.uncloned_fields(*attrs) if attrs.empty? @uncloned_fields ||= [:created_at, :updated_at, :deleted_at] else uncloned_fields.concat(attrs) end end |
.with_each_partition(&block) ⇒ Object
79 80 81 82 83 |
# File 'lib/active_document/base.rb', line 79 def self.with_each_partition(&block) database.partitions.each do |partition| database.with_partition(partition, &block) end end |
.with_partition(partition, &block) ⇒ Object
75 76 77 |
# File 'lib/active_document/base.rb', line 75 def self.with_partition(partition, &block) database.with_partition(partition, &block) end |
.writer(*attrs) ⇒ Object
213 214 215 216 217 218 219 |
# File 'lib/active_document/base.rb', line 213 def self.writer(*attrs) attrs.each do |attr| define_method("#{attr}=") do |value| attributes[attr] = value end end end |
Instance Method Details
#==(other) ⇒ Object
286 287 288 289 |
# File 'lib/active_document/base.rb', line 286 def ==(other) return false unless other.class == self.class attributes == other.attributes end |
#_dump(ignored) ⇒ Object
369 370 371 372 373 |
# File 'lib/active_document/base.rb', line 369 def _dump(ignored) attributes = @attributes.to_hash if @attributes saved_attributes = @saved_attributes.to_hash if @saved_attributes Marshal.dump([attributes, saved_attributes]) end |
#attributes ⇒ Object
263 264 265 |
# File 'lib/active_document/base.rb', line 263 def attributes @attributes ||= Marshal.load(Marshal.dump(saved_attributes)) end |
#changed?(field = nil) ⇒ Boolean
295 296 297 298 299 300 301 302 303 |
# File 'lib/active_document/base.rb', line 295 def changed?(field = nil) return false unless @attributes and @saved_attributes if field send(field) != saved.send(field) else attributes != saved_attributes end end |
#clone(changed_attributes = {}) ⇒ Object
310 311 312 313 314 315 316 317 |
# File 'lib/active_document/base.rb', line 310 def clone(changed_attributes = {}) cloned_attributes = Marshal.load(Marshal.dump(attributes)) uncloned_fields.each do |attr| cloned_attributes.delete(attr) end cloned_attributes.merge!(changed_attributes) self.class.new(cloned_attributes) end |
#database ⇒ Object
25 26 27 |
# File 'lib/active_document/base.rb', line 25 def database self.class.database end |
#delete ⇒ Object
354 355 356 357 |
# File 'lib/active_document/base.rb', line 354 def delete raise 'cannot delete a record without deleted_at attribute' unless respond_to?(:deleted_at) saved_attributes[:deleted_at] = Time.now end |
#deleted? ⇒ Boolean
365 366 367 |
# File 'lib/active_document/base.rb', line 365 def deleted? respond_to?(:deleted_at) and not deleted_at.nil? end |
#destroy ⇒ Object
349 350 351 |
# File 'lib/active_document/base.rb', line 349 def destroy database.delete(primary_key) end |
#new_record? ⇒ Boolean
291 292 293 |
# File 'lib/active_document/base.rb', line 291 def new_record? @saved_attributes.nil? end |
#partition ⇒ Object
93 94 95 |
# File 'lib/active_document/base.rb', line 93 def partition send(partition_by) if partition_by end |
#partition_by ⇒ Object
89 90 91 |
# File 'lib/active_document/base.rb', line 89 def partition_by self.class.partition_by end |
#read_attribute(attr) ⇒ Object
267 268 269 270 271 272 273 |
# File 'lib/active_document/base.rb', line 267 def read_attribute(attr) if @attributes.nil? saved_attributes[attr] else attributes[attr] end end |
#save(opts = {}) ⇒ Object
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/active_document/base.rb', line 327 def save(opts = {}) time = opts[:updated_at] || Time.now attributes[:updated_at] = time if respond_to?(:updated_at) attributes[:created_at] ||= time if respond_to?(:created_at) and new_record? opts = {} if changed?(:primary_key) or (partition_by and changed?(partition_by)) opts[:create] = true saved.destroy else opts[:create] = new_record? end @saved_attributes = attributes @attributes = nil @saved = nil database.set(primary_key, self, opts) rescue Bdb::DbError => e raise(ActiveDocument::DuplicatePrimaryKey, e) if e.code == Bdb::DB_KEYEXIST raise(e) end |
#saved ⇒ Object
305 306 307 308 |
# File 'lib/active_document/base.rb', line 305 def saved raise 'no saved attributes for new record' if new_record? @saved ||= self.class.new(saved_attributes) end |
#to_json(*args) ⇒ Object
282 283 284 |
# File 'lib/active_document/base.rb', line 282 def to_json(*args) attributes.to_json(*args) end |
#transaction(&block) ⇒ Object
33 34 35 |
# File 'lib/active_document/base.rb', line 33 def transaction(&block) self.class.transaction(&block) end |
#undelete ⇒ Object
360 361 362 363 |
# File 'lib/active_document/base.rb', line 360 def undelete raise 'cannot undelete a record without deleted_at attribute' unless respond_to?(:deleted_at) saved_attributes.delete(:deleted_at) end |
#update_attributes(attrs = {}) ⇒ Object
276 277 278 279 280 |
# File 'lib/active_document/base.rb', line 276 def update_attributes(attrs = {}) attrs.each do |field, value| self.send("#{field}=", value) end end |