memory_model 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -4
- data/Appraisals +9 -0
- data/Guardfile +7 -1
- data/README.md +5 -1
- data/Rakefile +12 -0
- data/gemfiles/rails_3.gemfile +8 -0
- data/gemfiles/rails_3.gemfile.lock +109 -0
- data/gemfiles/rails_4.gemfile +8 -0
- data/gemfiles/rails_4.gemfile.lock +117 -0
- data/lib/memory_model/base/actions/class_methods.rb +27 -0
- data/lib/memory_model/base/actions.rb +75 -0
- data/lib/memory_model/base/attributes.rb +87 -0
- data/lib/memory_model/base/auto_increment.rb +47 -0
- data/lib/memory_model/base/collectible.rb +26 -0
- data/lib/memory_model/base/conversion.rb +11 -0
- data/lib/memory_model/base/fields/field.rb +57 -0
- data/lib/memory_model/base/fields/field_set.rb +87 -0
- data/lib/memory_model/base/fields.rb +49 -0
- data/lib/memory_model/base/operations/comparisons.rb +25 -0
- data/lib/memory_model/base/operations.rb +10 -0
- data/lib/memory_model/base/persistence.rb +13 -11
- data/lib/memory_model/base.rb +58 -43
- data/lib/memory_model/collection/finders.rb +75 -0
- data/lib/memory_model/collection/index/multi.rb +61 -0
- data/lib/memory_model/collection/index/unique.rb +79 -0
- data/lib/memory_model/collection/index.rb +86 -0
- data/lib/memory_model/collection/initializers.rb +48 -0
- data/lib/memory_model/collection/loader_delegate.rb +63 -0
- data/lib/memory_model/collection/marshaled_record.rb +23 -0
- data/lib/memory_model/collection/operations.rb +82 -0
- data/lib/memory_model/collection.rb +18 -73
- data/lib/memory_model/version.rb +1 -1
- data/lib/memory_model.rb +7 -7
- data/memory_model.gemspec +8 -3
- data/spec/benchmark/benchmark.rb +126 -0
- data/spec/memory_model/base/{actionable_spec.rb → actions_spec.rb} +34 -103
- data/spec/memory_model/base/{attributable_spec.rb → attributes_spec.rb} +4 -6
- data/spec/memory_model/base/{collectable_spec.rb → collectible_spec.rb} +1 -1
- data/spec/memory_model/base/fieldable/field_set_spec.rb +23 -37
- data/spec/memory_model/base/fieldable/field_spec.rb +16 -16
- data/spec/memory_model/base/{fieldable_spec.rb → fields_spec.rb} +1 -1
- data/spec/memory_model/base/{comparable_spec.rb → operations/comparisons_spec.rb} +4 -4
- data/spec/memory_model/base/persistence_spec.rb +2 -2
- data/spec/memory_model/base_spec.rb +10 -9
- data/spec/memory_model/collection_spec.rb +24 -146
- data/spec/spec_helper.rb +11 -0
- data/spec/support/delegate_matcher.rb +40 -0
- metadata +120 -65
- data/.idea/.rakeTasks +0 -7
- data/.idea/dictionaries/jwaldrip.xml +0 -3
- data/.idea/encodings.xml +0 -5
- data/.idea/memory_model.iml +0 -47
- data/.idea/misc.xml +0 -8
- data/.idea/modules.xml +0 -9
- data/.idea/scopes/scope_settings.xml +0 -5
- data/.idea/vcs.xml +0 -7
- data/.idea/workspace.xml +0 -701
- data/lib/memory_model/base/actionable.rb +0 -95
- data/lib/memory_model/base/attributable.rb +0 -76
- data/lib/memory_model/base/collectable.rb +0 -22
- data/lib/memory_model/base/comparable.rb +0 -16
- data/lib/memory_model/base/fieldable/field.rb +0 -35
- data/lib/memory_model/base/fieldable/field_set.rb +0 -74
- data/lib/memory_model/base/fieldable.rb +0 -45
- data/lib/memory_model/base/versionable.rb +0 -17
- data/lib/memory_model/core_ext/object.rb +0 -5
- data/spec/memory_model/base/versionable_spec.rb +0 -31
- data/spec/memory_model/core_ext/object_spec.rb +0 -12
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'ice_nine'
|
2
|
-
require 'ice_nine/core_ext/object'
|
3
|
-
|
4
|
-
module MemoryModel::Base::Actionable
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
included do
|
8
|
-
define_model_callbacks :create, :update, :save, :destroy
|
9
|
-
attr_reader :timestamp
|
10
|
-
end
|
11
|
-
|
12
|
-
VALID_IVARS = [
|
13
|
-
:@deleted,
|
14
|
-
:@attributes,
|
15
|
-
:@timestamp,
|
16
|
-
:@version
|
17
|
-
]
|
18
|
-
|
19
|
-
def commit
|
20
|
-
@timestamp = Time.now
|
21
|
-
@version = SecureRandom.hex(6)
|
22
|
-
self.class.insert self
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def delete
|
27
|
-
@deleted = true
|
28
|
-
commit
|
29
|
-
freeze
|
30
|
-
end
|
31
|
-
|
32
|
-
def deleted?
|
33
|
-
!!@deleted
|
34
|
-
end
|
35
|
-
|
36
|
-
def deleted_at
|
37
|
-
deleted? ? @timestamp : nil
|
38
|
-
end
|
39
|
-
|
40
|
-
def destroy
|
41
|
-
run_callbacks :destroy do
|
42
|
-
delete
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def dup
|
47
|
-
deep_dup
|
48
|
-
end
|
49
|
-
|
50
|
-
def deep_dup
|
51
|
-
Marshal.load Marshal.dump self
|
52
|
-
end
|
53
|
-
|
54
|
-
def freeze
|
55
|
-
instance_variables.reject { |ivar| ivar.in? VALID_IVARS }.each do |ivar|
|
56
|
-
remove_instance_variable ivar if instance_variable_defined?(ivar)
|
57
|
-
end
|
58
|
-
instance_variables.each { |ivar| instance_variable_get(ivar).freeze }
|
59
|
-
deep_freeze
|
60
|
-
super
|
61
|
-
end
|
62
|
-
|
63
|
-
def save
|
64
|
-
callback = persisted? ? :update : :create
|
65
|
-
run_callbacks callback do
|
66
|
-
run_callbacks :save do
|
67
|
-
commit
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def restore
|
73
|
-
instance = frozen? ? self.dup : self
|
74
|
-
instance.instance_variable_set :@deleted, false
|
75
|
-
instance.save
|
76
|
-
instance
|
77
|
-
end
|
78
|
-
|
79
|
-
module ClassMethods
|
80
|
-
|
81
|
-
def create(attributes={})
|
82
|
-
new(attributes).save
|
83
|
-
end
|
84
|
-
|
85
|
-
def delete_all
|
86
|
-
all.map(&:delete).reject(&:deleted?).empty?
|
87
|
-
end
|
88
|
-
|
89
|
-
def destroy_all
|
90
|
-
all.map(&:destroy).reject(&:deleted?).empty?
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
module MemoryModel::Base::Attributable
|
2
|
-
extend ActiveSupport::Concern
|
3
|
-
include ActiveModel::AttributeMethods
|
4
|
-
include ActiveModel::Dirty
|
5
|
-
|
6
|
-
included do
|
7
|
-
attr_reader :attributes
|
8
|
-
delegate :to_hash, to: :attributes
|
9
|
-
attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
|
10
|
-
attribute_method_prefix 'clear_'
|
11
|
-
end
|
12
|
-
|
13
|
-
def has_attribute?(key)
|
14
|
-
case value = @attributes[key]
|
15
|
-
when NilClass, String
|
16
|
-
!value.nil?
|
17
|
-
else
|
18
|
-
value.present?
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def inspect
|
23
|
-
inspection = if @attributes
|
24
|
-
fields.reduce([]) { |array, name|
|
25
|
-
array << "#{name}: #{attribute_for_inspect(name)}" if has_attribute?(name)
|
26
|
-
array
|
27
|
-
}.join(", ")
|
28
|
-
else
|
29
|
-
"not initialized"
|
30
|
-
end
|
31
|
-
"#<#{[self.class, inspection].join(' ')}>"
|
32
|
-
end
|
33
|
-
|
34
|
-
def read_attribute(name)
|
35
|
-
@attributes[name]
|
36
|
-
end
|
37
|
-
|
38
|
-
alias :[] :read_attribute
|
39
|
-
|
40
|
-
def write_attribute(name, value)
|
41
|
-
raise MemoryModel::InvalidFieldError,
|
42
|
-
"#{name} is not a valid field" unless fields.include? name
|
43
|
-
raise MemoryModel::FieldReadOnlyError,
|
44
|
-
"#{name} is read only" if fields[name].options[:readonly]
|
45
|
-
|
46
|
-
send "#{name}_will_change!" unless value == read_attribute(name) || new_record?
|
47
|
-
@attributes[name] = value
|
48
|
-
end
|
49
|
-
|
50
|
-
alias :[]= :write_attribute
|
51
|
-
|
52
|
-
protected
|
53
|
-
|
54
|
-
def attribute_for_inspect(attr_name)
|
55
|
-
value = read_attribute(attr_name)
|
56
|
-
|
57
|
-
if value.is_a?(String) && value.length > 50
|
58
|
-
"#{value[0..50]}...".inspect
|
59
|
-
elsif value.is_a?(Date) || value.is_a?(Time)
|
60
|
-
value.to_s
|
61
|
-
else
|
62
|
-
value.inspect
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def reset_attribute_to_default!(attr)
|
69
|
-
write_attribute attr, fields.default_values(self).with_indifferent_access[attr]
|
70
|
-
end
|
71
|
-
|
72
|
-
def clear_attribute(attr)
|
73
|
-
write_attribute attr, nil
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
|
3
|
-
module MemoryModel::Base::Collectable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
extend ConcernedInheritance
|
6
|
-
|
7
|
-
inherited do
|
8
|
-
instance_variable_set :@collection, baseclass.collection
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
delegate :all, :find, :insert, :<<, :deleted, to: :collection
|
13
|
-
delegate :first, :last, to: :all
|
14
|
-
|
15
|
-
def collection
|
16
|
-
return nil if self == MemoryModel::Base
|
17
|
-
@collection ||= MemoryModel::Collection.new(self)
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module MemoryModel::Base::Comparable
|
2
|
-
|
3
|
-
def ==(other_object)
|
4
|
-
attributes.slice(*fields.comparable) ==
|
5
|
-
other_object.to_hash.with_indifferent_access.slice(*fields.comparable)
|
6
|
-
end
|
7
|
-
|
8
|
-
def !=(other_object)
|
9
|
-
!(self == other_object)
|
10
|
-
end
|
11
|
-
|
12
|
-
def ===(other_object)
|
13
|
-
other_object.kind_of?(self.class) && self == other_object
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
class MemoryModel::Base::Fieldable::Field
|
2
|
-
|
3
|
-
attr_reader :name, :options
|
4
|
-
delegate :inspect, to: :to_sym
|
5
|
-
|
6
|
-
def initialize(name, options={ })
|
7
|
-
@name = name.to_sym
|
8
|
-
@options = options.reverse_merge!({ readonly: false, comparable: true })
|
9
|
-
end
|
10
|
-
|
11
|
-
def ==(other_object)
|
12
|
-
self.to_sym == other_object.to_sym
|
13
|
-
end
|
14
|
-
|
15
|
-
def comparable?
|
16
|
-
!!@options[:comparable]
|
17
|
-
end
|
18
|
-
|
19
|
-
def default
|
20
|
-
@options[:default]
|
21
|
-
end
|
22
|
-
|
23
|
-
def readonly?
|
24
|
-
!!@options[:readonly]
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_sym
|
28
|
-
@name.to_sym
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_s
|
32
|
-
@name.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/hash/keys'
|
2
|
-
require 'set'
|
3
|
-
|
4
|
-
class MemoryModel::Base::Fieldable::FieldSet
|
5
|
-
|
6
|
-
Field = MemoryModel::Base::Fieldable::Field
|
7
|
-
|
8
|
-
attr_reader :fields
|
9
|
-
delegate :include?, to: :fields
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
@fields = []
|
13
|
-
end
|
14
|
-
|
15
|
-
def [](name)
|
16
|
-
@fields.find { |f| f.name == name.to_sym }
|
17
|
-
end
|
18
|
-
|
19
|
-
def <<(attr)
|
20
|
-
attr = Field.new(attr) unless attr.is_a? Field
|
21
|
-
@fields << attr
|
22
|
-
end
|
23
|
-
|
24
|
-
def add(attr, options={ })
|
25
|
-
@fields.delete_if { |f| f == attr }
|
26
|
-
@fields << Field.new(attr, options)
|
27
|
-
end
|
28
|
-
|
29
|
-
def comparable
|
30
|
-
@fields.select(&:comparable?).map(&:to_sym)
|
31
|
-
end
|
32
|
-
|
33
|
-
def inspect
|
34
|
-
to_a.inspect
|
35
|
-
end
|
36
|
-
|
37
|
-
def default_values(model, attributes={ })
|
38
|
-
@fields.reduce(attributes.symbolize_keys) do |attrs, field|
|
39
|
-
raise MemoryModel::ReadonlyFieldError if attrs[field.name].present? && field.readonly?
|
40
|
-
default = field.default.is_a?(Symbol) ? field.default.to_proc : field.default
|
41
|
-
attrs[field.name] ||= if default.nil?
|
42
|
-
nil
|
43
|
-
elsif default.is_a? String
|
44
|
-
default
|
45
|
-
elsif default.not_a?(::Proc)
|
46
|
-
raise ArgumentError, "#{default} must be a string, symbol, lamba or proc"
|
47
|
-
elsif default.lambda? && default.arity == 0
|
48
|
-
default.call
|
49
|
-
elsif default.arity.in? -1..0
|
50
|
-
model.instance_eval(&default)
|
51
|
-
elsif default.arity == 1
|
52
|
-
default.yield model
|
53
|
-
else
|
54
|
-
raise ArgumentError, "#{default} must have an arity of 0..1, got #{default.arity}"
|
55
|
-
end
|
56
|
-
attrs
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def to_a
|
61
|
-
@fields.map(&:to_sym)
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def method_missing(m, *args, &block)
|
67
|
-
if to_a.respond_to? m
|
68
|
-
to_a.send m, *args, &block
|
69
|
-
else
|
70
|
-
super
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
require 'active_support/dependencies/autoload'
|
3
|
-
require 'securerandom'
|
4
|
-
|
5
|
-
module MemoryModel::Base::Fieldable
|
6
|
-
extend ConcernedInheritance
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
extend ActiveSupport::Autoload
|
9
|
-
include ActiveModel::AttributeMethods
|
10
|
-
|
11
|
-
autoload :FieldSet
|
12
|
-
autoload :Field
|
13
|
-
|
14
|
-
inherited do
|
15
|
-
instance_variable_set :@fields, baseclass.fields
|
16
|
-
field :id, readonly: true, default: -> { SecureRandom.uuid }, comparable: false
|
17
|
-
end
|
18
|
-
|
19
|
-
module ClassMethods
|
20
|
-
def field(attr, options={ })
|
21
|
-
define_attribute_method attr unless instance_method_already_implemented? attr
|
22
|
-
fields.add(attr.to_sym, options)
|
23
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
24
|
-
def #{attr}
|
25
|
-
read_attribute :#{attr}
|
26
|
-
end
|
27
|
-
|
28
|
-
def #{attr}=(value)
|
29
|
-
write_attribute :#{attr}, value
|
30
|
-
end
|
31
|
-
RUBY
|
32
|
-
end
|
33
|
-
|
34
|
-
def fields
|
35
|
-
return nil if self == MemoryModel::Base
|
36
|
-
@fields ||= FieldSet.new
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
def fields
|
42
|
-
self.class.fields
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module MemoryModel::Base::Versionable
|
2
|
-
|
3
|
-
def versions
|
4
|
-
instances = self.class.collection.records.select { |i| i.id == self.id }
|
5
|
-
instances.reduce({ }) do |hash, instance|
|
6
|
-
hash[instance.version] = instance
|
7
|
-
hash
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def version
|
12
|
-
@version
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
# MemoryModel::Base::Immutable # todo!
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MemoryModel::Base::Versionable do
|
4
|
-
|
5
|
-
let(:model) do
|
6
|
-
Class.new(MemoryModel::Base)
|
7
|
-
end
|
8
|
-
let(:instance) do
|
9
|
-
model.new
|
10
|
-
end
|
11
|
-
before(:each) do
|
12
|
-
stub_const('MyModel', model)
|
13
|
-
end
|
14
|
-
|
15
|
-
describe '#versions' do
|
16
|
-
it 'should have a number of versions' do
|
17
|
-
10.times.each do |index|
|
18
|
-
instance.versions.size.should == index
|
19
|
-
instance.commit
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#version' do
|
25
|
-
it 'should be the latest version' do
|
26
|
-
3.times.each { instance.commit }
|
27
|
-
instance.version.should == instance.versions.keys.last
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|