ninja-model 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/Gemfile +2 -0
  2. data/README.md +1 -0
  3. data/Rakefile +38 -0
  4. data/lib/generators/ninja_model/model/model_generator.rb +19 -0
  5. data/lib/generators/ninja_model/model/templates/model.rb +7 -0
  6. data/lib/generators/ninja_model/scaffold/scaffold_generator.rb +69 -0
  7. data/lib/generators/ninja_model.rb +12 -0
  8. data/lib/ninja-model.rb +1 -0
  9. data/lib/ninja_model/adapters/abstract_adapter.rb +63 -0
  10. data/lib/ninja_model/adapters/adapter_manager.rb +67 -0
  11. data/lib/ninja_model/adapters/adapter_pool.rb +128 -0
  12. data/lib/ninja_model/adapters/adapter_specification.rb +11 -0
  13. data/lib/ninja_model/adapters.rb +70 -0
  14. data/lib/ninja_model/associations/active_record_proxy.rb +53 -0
  15. data/lib/ninja_model/associations/association_proxy.rb +8 -0
  16. data/lib/ninja_model/associations/belongs_to_association.rb +31 -0
  17. data/lib/ninja_model/associations/has_many_association.rb +36 -0
  18. data/lib/ninja_model/associations/has_one_association.rb +19 -0
  19. data/lib/ninja_model/associations/ninja_model_proxy.rb +46 -0
  20. data/lib/ninja_model/associations.rb +198 -0
  21. data/lib/ninja_model/attributes.rb +134 -0
  22. data/lib/ninja_model/base.rb +106 -0
  23. data/lib/ninja_model/callbacks.rb +14 -0
  24. data/lib/ninja_model/configuration.rb +20 -0
  25. data/lib/ninja_model/core_ext/symbol.rb +7 -0
  26. data/lib/ninja_model/errors.rb +5 -0
  27. data/lib/ninja_model/identity.rb +24 -0
  28. data/lib/ninja_model/log_subscriber.rb +18 -0
  29. data/lib/ninja_model/persistence.rb +76 -0
  30. data/lib/ninja_model/predicate.rb +43 -0
  31. data/lib/ninja_model/railtie.rb +27 -0
  32. data/lib/ninja_model/reflection.rb +118 -0
  33. data/lib/ninja_model/relation/finder_methods.rb +74 -0
  34. data/lib/ninja_model/relation/query_methods.rb +62 -0
  35. data/lib/ninja_model/relation/spawn_methods.rb +59 -0
  36. data/lib/ninja_model/relation.rb +80 -0
  37. data/lib/ninja_model/scoping.rb +50 -0
  38. data/lib/ninja_model/validation.rb +38 -0
  39. data/lib/ninja_model/version.rb +3 -0
  40. data/lib/ninja_model.rb +38 -0
  41. data/spec/ninja_model/adapters/adapter_pool_spec.rb +72 -0
  42. data/spec/ninja_model/adapters_spec.rb +8 -0
  43. data/spec/ninja_model/attributes_spec.rb +85 -0
  44. data/spec/ninja_model/base_spec.rb +66 -0
  45. data/spec/ninja_model/identity_spec.rb +41 -0
  46. data/spec/ninja_model/persistence_spec.rb +9 -0
  47. data/spec/ninja_model/predicate_spec.rb +13 -0
  48. data/spec/ninja_model/query_methods_spec.rb +76 -0
  49. data/spec/ninja_model/relation_spec.rb +26 -0
  50. data/spec/ninja_model/scoping_spec.rb +40 -0
  51. data/spec/ninja_model_spec.rb +11 -0
  52. data/spec/spec_helper.rb +9 -0
  53. data/spec/support/active_model_lint.rb +17 -0
  54. metadata +214 -0
@@ -0,0 +1,46 @@
1
+ module NinjaModel
2
+ module Associations
3
+ class NinjaModelProxy
4
+ attr_reader :proxy_klass
5
+ def initialize(active_record)
6
+ @klass = active_record
7
+ @klass.class_eval do
8
+ def ninja_proxy
9
+ @ninja_proxy ||= begin
10
+ self.class.ninja_proxy.instance(self)
11
+ end
12
+ @ninja_proxy.attributes = self.attributes.delete_if { |k,v| k.eql?('id') }
13
+ @ninja_proxy
14
+ end
15
+ end
16
+
17
+ @proxy_klass = active_record.parent.const_set("#{@klass.model_name}Proxy", Class.new(NinjaModel::Base))
18
+
19
+ @klass.columns_hash.each_pair do |k,v|
20
+ @proxy_klass.send :attribute, k, v.type, v.default, @proxy_klass
21
+ end
22
+ end
23
+
24
+ def instance(obj)
25
+ proxy = @proxy_klass.new
26
+ proxy.send :instantiate, {'attributes' => obj.attributes}
27
+ proxy
28
+ end
29
+
30
+ def handle_association(macro, association_id, options)
31
+ unless macro.eql?(:belongs_to)
32
+ options = {:foreign_key => derive_foreign_key}.merge(options)
33
+ end
34
+
35
+ @proxy = nil
36
+ @proxy_klass.send macro, association_id, options
37
+ end
38
+
39
+ private
40
+
41
+ def derive_foreign_key
42
+ "#{@klass.name.underscore}_id".to_sym
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,198 @@
1
+ require 'active_support/concern'
2
+ require 'ninja_model/associations/active_record_proxy'
3
+ require 'ninja_model/associations/ninja_model_proxy'
4
+
5
+ module ActiveRecord
6
+ module Associations
7
+ module ClassMethods
8
+ alias :has_one_without_ninja_model :has_one
9
+ def has_one(association_id, options = {})
10
+ if ninja_model?(:has_one, options[:class_name] || association_id)
11
+ ninja_proxy.handle_association(:has_one, association_id, options)
12
+ else
13
+ has_one_without_ninja_model(association_id, options)
14
+ end
15
+ end
16
+
17
+ def ninja_proxy
18
+ read_inheritable_attribute(:ninja_proxy) || write_inheritable_attribute(:ninja_proxy, NinjaModel::Associations::NinjaModelProxy.new(self))
19
+ end
20
+
21
+ private
22
+
23
+ def ninja_model?(macro, association)
24
+ klass = association.to_s.camelize
25
+ klass = klass.singularize unless [:has_one, :belongs_to].include?(macro)
26
+ klass = klass.constantize
27
+ klass.ancestors.include?(NinjaModel::Base)
28
+ end
29
+ end
30
+
31
+ def method_missing(method, *args)
32
+ begin
33
+ super
34
+ rescue NoMethodError => ex
35
+ if self.class.read_inheritable_attribute(:ninja_proxy) && ninja_proxy.respond_to?(method)
36
+ ninja_proxy.send(method, *args)
37
+ else
38
+ raise ex
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ module Reflection
45
+ module ClassMethods
46
+ alias :reflect_on_association_without_ninja_model :reflect_on_association
47
+ def reflect_on_association(association)
48
+ if read_inheritable_attribute(:ninja_proxy) && ninja_proxy.proxy_klass.reflections.include?(association)
49
+ ninja_proxy.proxy_klass.reflect_on_association(association)
50
+ else
51
+ reflect_on_association_without_ninja_model(association)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ module NinjaModel
59
+ module Associations
60
+ extend ActiveSupport::Concern
61
+
62
+ autoload :AssociationProxy, 'ninja_model/associations/association_proxy'
63
+ autoload :HasOneAssociation, 'ninja_model/associations/has_one_association'
64
+ autoload :HasManyAssociation, 'ninja_model/associations/has_many_association'
65
+ autoload :BelongsToAssociation, 'ninja_model/associations/belongs_to_association'
66
+
67
+
68
+ module ClassMethods
69
+ def has_one(association_id, options = {})
70
+ if ninja_model?(:has_one, options[:class_name] || association_id)
71
+ reflection = create_has_one_reflection(association_id, options)
72
+ association_accessor_methods(reflection, HasOneAssociation)
73
+ #association_constructor_method(:build, reflection, HasOneAssociation)
74
+ #association_constructor_method(:create, reflection, HasOneAssociation)
75
+ #configure_dependency_for_has_one(reflection)
76
+ else
77
+ #puts "Setting up has_one proxy for #{association_id}"
78
+ proxy.handle_association(:has_one, association_id, options)
79
+ end
80
+ end
81
+
82
+ def belongs_to(association_id, options = {})
83
+ if ninja_model?(:belongs_to, options[:class_name] || association_id)
84
+ reflection = create_belongs_to_reflection(association_id, options)
85
+ association_accessor_methods(reflection, BelongsToAssociation)
86
+ #association_constructor_method(:build, reflection, BelongsToAssociation)
87
+ #association_constructor_method(:create, reflection, BelongsToAssociation)
88
+ else
89
+ proxy.handle_association(:belongs_to, association_id, options)
90
+ end
91
+ end
92
+
93
+ def has_many(association_id, options = {})
94
+ if ninja_model?(:has_many, association_id)
95
+ reflection = create_has_many_reflection(association_id, options)
96
+ collection_accessor_methods(reflection, HasManyAssociation)
97
+ #collection_accessor_methods(reflection, HasManyAssociation)
98
+ else
99
+ proxy.handle_association(:has_many, association_id, options)
100
+ end
101
+ end
102
+
103
+ def proxy
104
+ read_inheritable_attribute(:proxy) || write_inheritable_attribute(:proxy, ActiveRecordProxy.new(self))
105
+ end
106
+
107
+ private
108
+
109
+ def create_has_one_reflection(association, options = {})
110
+ create_reflection(:has_one, association, options, self)
111
+ end
112
+
113
+ def create_has_many_reflection(association, options = {})
114
+ create_reflection(:has_many, association, options, self)
115
+ #options[:extend] = create_extension_modules(association, extension
116
+ end
117
+
118
+ def create_belongs_to_reflection(association, options = {})
119
+ create_reflection(:belongs_to, association, options, self)
120
+ end
121
+
122
+ def association_accessor_methods(reflection, association_proxy_class)
123
+ redefine_method(reflection.name) do |*params|
124
+ association = association_instance_get(reflection.name)
125
+
126
+ if association.nil?
127
+ association = association_proxy_class.new(self, reflection)
128
+ retval = association.reload
129
+ if retval.nil? and association_proxy_class == BelongsToAssociation
130
+ association_instance_set(reflection.name, nil)
131
+ return nil
132
+ end
133
+ association_instance_set(reflection.name, association)
134
+ end
135
+ association.target.nil? ? nil : association
136
+ end
137
+
138
+ redefine_method("loaded_#{reflection.name}?") do
139
+ association = association_instance_get(reflection.name)
140
+ association && association.loaded?
141
+ end
142
+
143
+ redefine_method("#{reflection.name}=") do |new_value|
144
+ association = association_instance_get(reflection.name)
145
+ if association.nil? || association.target != new_value
146
+ association = association_proxy_class.new(self, reflection)
147
+ end
148
+
149
+ association.replace(new_value)
150
+ association_instance_set(reflection.name, new_value.nil? ? nil : association)
151
+ end
152
+
153
+ redefine_method("set_#{reflection.name}_target") do |target|
154
+ return if target.nil? and association_proxy_class == BelongsToAssociation
155
+ association = association_proxy_class.new(self, reflection)
156
+ association.target = target
157
+ association_instance_set(reflection.name, association)
158
+ end
159
+ end
160
+
161
+ def collection_accessor_methods(reflection, association_proxy_class)
162
+ collection_reader_method(reflection, association_proxy_class)
163
+ end
164
+
165
+ def collection_reader_method(reflection, association_proxy_class)
166
+ redefine_method(reflection.name) do |*params|
167
+ association = association_instance_get(reflection.name)
168
+
169
+ if association.nil?
170
+ association = association_proxy_class.new(self, reflection)
171
+ end
172
+ association_instance_set(reflection.name, association)
173
+ association
174
+ end
175
+ end
176
+ end
177
+
178
+ def association_instance_get(name)
179
+ ivar = "@#{name}"
180
+ if instance_variable_defined?(ivar)
181
+ association = instance_variable_get(ivar)
182
+ association if association.respond_to?(:loaded?)
183
+ end
184
+ end
185
+
186
+ def association_instance_set(name, association)
187
+ instance_variable_set("@#{name}", association)
188
+ end
189
+
190
+ def method_missing(method, *args)
191
+ if self.class.read_inheritable_attribute(:proxy) && proxy.respond_to?(method)
192
+ proxy.send(method, *args)
193
+ else
194
+ super
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,134 @@
1
+ require 'active_support'
2
+ require 'active_model/attribute_methods'
3
+
4
+ module NinjaModel
5
+ class Attribute
6
+ attr_reader :name, :type, :default, :primary_key
7
+ alias :primary_key? :primary_key
8
+ alias :primary :primary_key
9
+
10
+ def initialize(name, type, default, owner_class, options)
11
+ @name, @type, @default = name.to_s, type, default
12
+ @owner_class = owner_class
13
+ @options = options
14
+ @primary_key = options.key?(:primary_key) && options[:primary_key]
15
+ end
16
+
17
+ def define_methods!
18
+ @owner_class.define_attribute_methods(true)
19
+ @owner_class.primary_key = name.to_sym if @primary_key
20
+ end
21
+
22
+ def convert(value)
23
+ case type
24
+ when :string then value
25
+ when :text then value
26
+ when :integer then value.to_i rescue value ? 1 : 0
27
+ when :float then value.to_f
28
+ when :date then ActiveRecord::ConnectionAdapters::Column.string_to_date(value)
29
+ else value
30
+ end
31
+ end
32
+ end
33
+
34
+ module Attributes
35
+ extend ActiveSupport::Concern
36
+ include ActiveModel::AttributeMethods
37
+
38
+ module ClassMethods
39
+ def attribute(name, data_type, *args)
40
+ name = name.to_s
41
+ opts = args.extract_options!
42
+ default = args.first unless args.blank?
43
+ new_attr = Attribute.new(name, data_type, default, self, opts)
44
+ self.model_attributes << new_attr
45
+ new_attr.define_methods!
46
+ end
47
+
48
+ def define_attribute_methods(force = false)
49
+ return unless self.model_attributes
50
+ undefine_attribute_methods if force
51
+ super(self.model_attributes.map { |attr| attr.name })
52
+ end
53
+
54
+ def columns
55
+ model_attributes
56
+ end
57
+
58
+ def model_attributes_hash
59
+ @attributes_hash ||= HashWithIndifferentAccess[model_attributes.map { |attribute| [attribute.name, attribute] }]
60
+ end
61
+
62
+ alias :columns_hash :model_attributes_hash
63
+
64
+ def attribute_names
65
+ @attribute_names ||= model_attributes.map { |attribute| attribute.name }
66
+ end
67
+
68
+ alias :column_names :attribute_names
69
+ end
70
+
71
+ included do
72
+ class_inheritable_accessor :model_attributes
73
+ self.model_attributes = []
74
+ attribute_method_suffix('', '=')
75
+ end
76
+
77
+ def attributes_from_model_attributes
78
+ self.class.model_attributes.inject({}) do |result, attr|
79
+ result[attr.name] = attr.default unless attr.name == self.class.primary_key
80
+ result
81
+ end
82
+ end
83
+
84
+ def write_attribute(name, value)
85
+ name = name.to_s
86
+ if a = self.class.model_attributes_hash[name]
87
+ @attributes[name] = value
88
+ else
89
+ raise NoMethodError, "Unknown attribute #{name.inspect}"
90
+ end
91
+ end
92
+
93
+ def read_attribute(name)
94
+ name = name.to_s
95
+ if !(value = @attributes[name]).nil?
96
+ self.class.model_attributes_hash[name].convert(@attributes[name])
97
+ else
98
+ nil
99
+ end
100
+ end
101
+
102
+ def [](attr_name)
103
+ read_attribute(attr_name)
104
+ end
105
+
106
+ def []=(attr_name, value)
107
+ write_attribute(attr_name, value)
108
+ end
109
+
110
+ def attributes=(new_attributes)
111
+ return unless new_attributes.is_a?(Hash)
112
+ attributes = new_attributes.stringify_keys
113
+
114
+ attributes.each do |k,v|
115
+ respond_to?("#{k}=".to_sym) ? send("#{k}=".to_sym, v) : raise(UnknownAttributeError, "unknown attribute: #{k}")
116
+ end
117
+ end
118
+
119
+ def attribute_method?(name)
120
+ name = name.to_s
121
+ self.class.model_attributes_hash.key?(name)
122
+ end
123
+
124
+ private
125
+
126
+ def attribute(name)
127
+ read_attribute(name)
128
+ end
129
+
130
+ def attribute=(name, value)
131
+ write_attribute(name, value)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,106 @@
1
+ module NinjaModel
2
+ class Base
3
+ include Attributes
4
+ include Callbacks
5
+ include Identity
6
+ include Persistence
7
+ include Scoping
8
+ include Validation
9
+ include Adapters
10
+ include Associations
11
+ include Reflection
12
+ include ActiveRecord::Aggregations
13
+ extend ActiveModel::Translation
14
+ extend ActiveModel::Naming
15
+
16
+ class_inheritable_accessor :default_scoping, :instance_writer => false
17
+ self.default_scoping = []
18
+
19
+ class << self
20
+
21
+ delegate :find, :first, :last, :all, :exists?, :to => :scoped
22
+ delegate :where, :order, :limit, :to => :scoped
23
+
24
+ def configuration_path
25
+ @config_path ||= File.join(Rails.root, "config/ninja_model.yml")
26
+ end
27
+
28
+ def configuration_path=(new_path)
29
+ @config_path = new_path
30
+ end
31
+
32
+ def configuration
33
+ require 'erb'
34
+ require 'yaml'
35
+ @configuration ||= YAML::load(ERB.new(IO.read(configuration_path)).result).with_indifferent_access
36
+ end
37
+
38
+ def relation
39
+ @relation ||= Relation.new(self)
40
+ end
41
+
42
+ def logger
43
+ ::NinjaModel.logger
44
+ end
45
+
46
+ def unscoped
47
+ block_given? ? relation.scoping { yield } : relation
48
+ end
49
+
50
+ def scoped_methods
51
+ key = "#{self}_scoped_methods".to_sym
52
+ Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
53
+ end
54
+
55
+ def default_scope(options = {})
56
+ reset_scoped_methods
57
+ self.default_scoping << build_finder_relation(options, default_scoping.pop)
58
+ end
59
+
60
+ def current_scoped_methods
61
+ last = scoped_methods.last
62
+ last.is_a?(Proc) ? unscoped(&last) : last
63
+ end
64
+
65
+ def reset_scoped_methods
66
+ Thread.current["#{self}_scoped_methods".to_sym] = nil
67
+ end
68
+
69
+ private
70
+
71
+ def build_finder_relation(options = {}, scope = nil)
72
+ relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) : options
73
+ relation = scope.merge(relation) if scope
74
+ relation
75
+ end
76
+ end
77
+
78
+ def attributes
79
+ attrs = {}
80
+ self.class.attribute_names.each { |name|
81
+ attrs[name] = read_attribute(name)
82
+ }
83
+ attrs
84
+ end
85
+
86
+ def initialize(attributes = nil)
87
+ @attributes = attributes_from_model_attributes
88
+ self.attributes = attributes unless attributes.nil?
89
+ @persisted = false
90
+ @readonly = true
91
+ @destroyed = false
92
+ result = yield self if block_given?
93
+ _run_initialize_callbacks
94
+ result
95
+ end
96
+
97
+ def instantiate(record)
98
+ @attributes = record.stringify_keys
99
+ @readonly = @destroyed = false
100
+ @persisted = true
101
+ self
102
+ end
103
+ end
104
+ end
105
+
106
+ require 'ninja_model/core_ext/symbol'
@@ -0,0 +1,14 @@
1
+ require 'active_support'
2
+ require 'active_model/callbacks'
3
+
4
+ module NinjaModel
5
+ module Callbacks
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ extend ActiveModel::Callbacks
10
+ define_model_callbacks :initialize, :find, :touch, :only => :after
11
+ define_model_callbacks :save, :create, :update, :destroy, :validation
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module NinjaModel
2
+
3
+ mattr_accessor :configuration
4
+
5
+ class Configuration
6
+ attr_accessor :config_file_path, :adapter_path, :specs
7
+
8
+ def self.create
9
+ NinjaModel.configuration ||= new
10
+ end
11
+
12
+ private
13
+
14
+ def initialize
15
+ @config_file_path = 'config/ninja_model.yml'
16
+ @adapter_path = 'ninja_model/adapters'
17
+ @specs = {}
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ class Symbol
2
+ NinjaModel::Predicate::PREDICATES.each do |predicate|
3
+ define_method(predicate) do |*args|
4
+ NinjaModel::Predicate.new(self, predicate, *args)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module NinjaModel
2
+ class NinjaModelError < StandardError; end
3
+ class AdapterNotSpecified < NinjaModelError; end
4
+ class ConnectionTimeoutError < NinjaModelError; end
5
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_support'
2
+
3
+ module NinjaModel
4
+ module Identity
5
+ extend ActiveSupport::Concern
6
+ include ActiveModel::AttributeMethods
7
+
8
+ included do
9
+ class_inheritable_accessor :primary_key
10
+ self.primary_key = :id
11
+ undef_method(:id) if method_defined?(:id)
12
+ end
13
+
14
+ def to_param
15
+ send(self.class.primary_key).to_s if persisted?
16
+ end
17
+
18
+ def to_key
19
+ key = nil
20
+ key = send(self.class.primary_key) if persisted?
21
+ [key] if key
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module NinjaModel
2
+ class LogSubscriber < ActiveSupport::LogSubscriber
3
+ def xml(event)
4
+ return unless logger.debug?
5
+
6
+ name = '%s (%.1fms)' % [event.payload[:name], event.duration]
7
+ xml = event.payload[:xml]
8
+
9
+ debug " #{name} #{xml}"
10
+ end
11
+
12
+ def logger
13
+ NinjaModel::Base.logger
14
+ end
15
+ end
16
+ end
17
+
18
+ ActiveRecord::LogSubscriber.attach_to :ninja_model
@@ -0,0 +1,76 @@
1
+ require 'active_support'
2
+
3
+ module NinjaModel
4
+ module Persistence
5
+ extend ActiveSupport::Concern
6
+ include ActiveModel::AttributeMethods
7
+
8
+ module ClassMethods
9
+ def get(rel)
10
+ end
11
+
12
+ def persist_with(adapter)
13
+
14
+ end
15
+ end
16
+
17
+ included do
18
+ class_inheritable_accessor :persistence_adapter
19
+ end
20
+
21
+ def save(*)
22
+ run_callbacks :save do
23
+ create_or_update
24
+ end
25
+ end
26
+
27
+ def create_or_update
28
+ if new_record?
29
+ create
30
+ else
31
+ update
32
+ end
33
+ end
34
+
35
+ def create
36
+ run_callbacks :create do
37
+ if self.class.adapter.create(self)
38
+ @persisted = true
39
+ end
40
+ @persisted
41
+ end
42
+ end
43
+
44
+ def update
45
+ self.class.adapter.update(self)
46
+ end
47
+
48
+ def new_record?
49
+ !@persisted
50
+ end
51
+
52
+ def destroyed?
53
+ @destroyed
54
+ end
55
+
56
+ def persisted?
57
+ @persisted && !destroyed?
58
+ end
59
+
60
+ def destroy
61
+ if self.class.adapter.destroy(self)
62
+ @destroyed = true
63
+ end
64
+ @destroyed
65
+ end
66
+
67
+ def reload
68
+ self.class.adapter.reload(self)
69
+ end
70
+
71
+ def update_attributes(attributes)
72
+ self.attributes = attributes
73
+ save
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,43 @@
1
+ module NinjaModel
2
+ class Predicate
3
+
4
+ PREDICATES = [:eq, :ne, :gt, :gte, :lt, :lte, :in]
5
+
6
+ attr_reader :attribute, :method, :value
7
+
8
+ def initialize(attribute, method, *args)
9
+ @attribute = attribute
10
+ @method = method
11
+ @valued = !args.blank?
12
+ @value = args.blank? ? nil : args.first
13
+ end
14
+
15
+ def value=(value)
16
+ @value = value
17
+ @valued = true
18
+ end
19
+
20
+ def has_value?
21
+ @valued
22
+ end
23
+
24
+ def test(suspect)
25
+ case method
26
+ when :eq
27
+ suspect.eql?(value)
28
+ when :ne
29
+ !suspect.eql?(value)
30
+ when :gt
31
+ suspect > value
32
+ when :gte
33
+ suspect >= value
34
+ when :lt
35
+ suspect < value
36
+ when :lte
37
+ suspect <= value
38
+ when :in
39
+ value.include?(suspect)
40
+ end
41
+ end
42
+ end
43
+ end