simple_model 1.2.5 → 1.2.7

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.
data/Gemfile CHANGED
@@ -2,5 +2,4 @@ source "http://rubygems.org"
2
2
 
3
3
 
4
4
  # Specify your gem's dependencies in simple_model.gemspec
5
- gemspec
6
-
5
+ gemspec
@@ -1,13 +1,15 @@
1
- require 'simple_model/exceptions'
2
1
  module SimpleModel
3
2
  module Attributes
4
3
  include ExtendCore
5
4
  extend ActiveSupport::Concern
6
5
  include ActiveModel::AttributeMethods
7
-
6
+
8
7
  def initialize(*attrs)
9
8
  attrs = attrs.extract_options!
10
- set(attributes_with_for_init(attrs))
9
+ attrs = attributes_with_for_init(attrs)
10
+ attrs = self.class.before_initialize.call(self,attrs) if self.class.before_initialize
11
+ set(attrs)
12
+ self.class.after_initialize.call(self) if self.class.after_initialize
11
13
  end
12
14
 
13
15
  # Returns true if attribute has been initialized
@@ -59,6 +61,35 @@ module SimpleModel
59
61
  def allow_set_default?(d,k,v)
60
62
  (v[:default] && v[:initialize] && (d[k].blank? && (self.class.alias_attributes[k].blank? || d.key?(self.class.alias_attributes[k]) && d[self.class.alias_attributes[k]].blank?)))
61
63
  end
64
+
65
+ private
66
+
67
+ def allow_attribute_action?(obj,val,options)
68
+ return true if (options[:if].blank? && options[:unless].blank?)
69
+ b = true
70
+ if options[:if].is_a?(Symbol)
71
+ if options[:if] == :blank
72
+ b = (b && val.blank?)
73
+ else
74
+ b = (b && send(options[:if]))
75
+ end
76
+ end
77
+ b = (b && options[:if].call(obj,val)) if options[:if].is_a?(Proc)
78
+ if options[:unless].is_a?(Symbol)
79
+ if options[:unless] == :blank
80
+ b = (b && !val.blank?)
81
+ else
82
+ b = (b && !send(options[:unless]))
83
+ end
84
+ end
85
+ b = (b && !options[:unless].call(obj,val)) if options[:unless].is_a?(Proc)
86
+ b
87
+ end
88
+
89
+ # Rails 3.2 + required when searching for attributes in from inherited classes/cmodles
90
+ def attribute(name)
91
+ attributes[name.to_sym]
92
+ end
62
93
 
63
94
  module ClassMethods
64
95
  # Creates a new instance where the attributes store is set to object
@@ -123,8 +154,8 @@ module SimpleModel
123
154
  # re-run to occur ONLY IN RAILS 3.0.
124
155
  def add_defined_attribute(attr,options)
125
156
  self.defined_attributes[attr] = options
126
- @attribute_methods_generated = nil if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
127
- define_attribute_methods self.defined_attributes.keys
157
+ @attribute_methods_generated = nil #if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
158
+ define_attribute_methods(self.defined_attributes.keys)
128
159
  end
129
160
 
130
161
  # builds the setter and getter methods
@@ -141,10 +172,11 @@ module SimpleModel
141
172
  add_defined_attribute(attr,options)
142
173
  options = default_attribute_settings.merge(options) if options[:on_get].blank?
143
174
  define_method(attr) do
144
- if (options.key?(:default) && (!self.initialized?(attr) || (!options[:allow_blank] && self.attributes[attr].blank?)))
145
- self.attributes[attr] = fetch_default_value(options[:default])
175
+ val = self.attributes[attr]
176
+ if (options.key?(:default) && (!self.initialized?(attr) || (!options[:allow_blank] && val.blank?)))
177
+ val = self.attributes[attr] = fetch_default_value(options[:default])
146
178
  end
147
- options[:on_get].call(self,self.attributes[attr])
179
+ options[:on_get].call(self,val)
148
180
  end
149
181
  define_method("#{attr.to_s}?") do
150
182
  val = self.send(attr)
@@ -164,16 +196,14 @@ module SimpleModel
164
196
  add_defined_attribute(attr,options)
165
197
  options = default_attribute_settings.merge(options) if (options[:on_set].blank? || options[:after_set].blank?)
166
198
  define_method("#{attr.to_s}=") do |val|
167
- val = fetch_default_value(options[:default]) if (!options[:allow_blank] && options.key?(:default) && val.blank?)
168
- begin
169
- val = options[:on_set].call(self,val)
170
- rescue NoMethodError => e
171
- raise ArgumentError, "#{val} could not be set for #{attr}: #{e.message}"
199
+ if allow_attribute_action?(self,val,options)
200
+ val = fetch_default_value(options[:default]) if (!options[:allow_blank] && options.key?(:default) && val.blank?)
201
+ val = options[:on_set].call(self,val) unless (val.blank? && !options[:allow_blank] )
202
+ will_change = "#{attr}_will_change!".to_sym
203
+ self.send(will_change) if (initialized?(attr) && val != self.attributes[attr])
204
+ self.attributes[attr] = val
205
+ options[:after_set].call(self,val) if options[:after_set]
172
206
  end
173
- will_change = "#{attr}_will_change!".to_sym
174
- self.send(will_change) if (initialized?(attr) && val != self.attributes[attr])
175
- self.attributes[attr] = val
176
- options[:after_set].call(self,val) if options[:after_set]
177
207
  end
178
208
  end
179
209
 
@@ -181,14 +211,14 @@ module SimpleModel
181
211
  :has_attribute => {:alias => :has_attributes},
182
212
  :has_boolean => {:cast_to => :to_b, :alias => :has_booleans},
183
213
  :has_currency => {:cast_to => :to_d, :alias => :has_currencies},
184
- :has_date => {:cast_to => :to_date, :alias => :has_dates},
214
+ :has_date => {:cast_to => :to_date, :alias => :has_dates} ,
185
215
  :has_decimal => {:cast_to => :to_d, :alias => :has_decimals},
186
216
  :has_float => {:cast_to => :to_f, :alias => :has_floats},
187
217
  :has_int => {:cast_to => :to_i, :alias => :has_ints},
188
218
  :has_time => {:cast_to => :to_time, :alias => :has_times}
189
219
  }
190
220
 
191
- AVAILABLE_ATTRIBUTE_METHODS.each do |method,method_options|
221
+ AVAILABLE_ATTRIBUTE_METHODS.each do |method,method_options|
192
222
  define_method(method) do |*attributes|
193
223
  options = default_attribute_settings.merge(attributes.extract_options!)
194
224
  options[:on_set] = lambda {|obj,val| val.send(method_options[:cast_to]) } if method_options[:cast_to]
@@ -209,20 +239,57 @@ module SimpleModel
209
239
  end
210
240
  end
211
241
 
242
+ # A hook to perform actions on the pending attributes or the object before
243
+ # the pending attributes have been initialized.
244
+ # Expects an lambda that accept the object, the pending attributes hash and
245
+ # should return a hash to be set
246
+ # EX: lambda {|obj,attrs| attrs.select{|k,v| !v.blank?}}
247
+ def before_initialize
248
+ @before_initialize
249
+ end
250
+
251
+ # Expects an lambda that accept the object, the pending attributes hash and
252
+ # should return a hash to be set
253
+ # EX: lambda {|obj,attrs| attrs.select{|k,v| !v.blank?}}
254
+ def before_initialize=before_initialize
255
+ raise TypeError "before_initialize must be a lambda that accepts the attirbutes to be initialize" unless before_initialize.is_a?(Proc)
256
+ @before_initialize = before_initialize
257
+ end
258
+
259
+ # A hook to perform actions after all attributes have been initialized
260
+ # Expects an lambda that accept the object and the pending attributes hash
261
+ # EX: lambda{|obj| puts "initialized"}
262
+ def after_initialize
263
+ @after_initialize
264
+ end
265
+
266
+ # Expects an lambda that accept the object and the pending attributes hash
267
+ # EX: lambda{|obj| puts "initialized"}
268
+ def after_initialize=after_initialize
269
+ raise TypeError "after_initalize must be a Proc" unless after_initialize.is_a?(Proc)
270
+ @after_initialize = after_initialize
271
+ end
272
+
273
+
274
+
212
275
  # Must inherit super's defined_attributes and alias_attributes
213
276
  # Rails 3.0 does some weird stuff with ActiveModel::Dirty so we need a
214
277
  # hack to keep things working when a class in inherits from a super that
215
278
  # has ActiveModel::Dirty included
216
279
  def inherited(base)
217
280
  # Rails 3.0 Hack
218
- if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
219
- base.send(:include, ActiveModel::Dirty)
281
+ if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
220
282
  base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
221
283
  base.attribute_method_affix :prefix => 'reset_', :suffix => '!'
222
284
  end
285
+ base.send(:include, ActiveModel::Dirty)
286
+
287
+ self.defined_attributes.each do |attr,options|
288
+ base.create_attribute_methods([attr],options)
289
+ end
223
290
 
224
- base.defined_attributes = self.defined_attributes.merge(base.defined_attributes)
225
291
  base.alias_attributes = self.alias_attributes.merge(base.alias_attributes )
292
+ super
226
293
  end
227
294
  end
228
295
 
@@ -240,8 +307,8 @@ module SimpleModel
240
307
 
241
308
  # Rails 3.0 Hack
242
309
  if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
243
- base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
244
- base.attribute_method_affix :prefix => 'reset_', :suffix => '!'
310
+ base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
311
+ base.attribute_method_affix :prefix => 'reset_', :suffix => '!'
245
312
  end
246
313
  end
247
314
  end
@@ -154,7 +154,7 @@ require 'active_support/core_ext/object/blank'
154
154
  default_options.merge!(methods.extract_options!)
155
155
  actions = [action,"#{action}!".to_sym]
156
156
  actions.each do |a|
157
- define_method(a) do |opts={}|
157
+ define_method(a) do |opts = {}|
158
158
  options = default_options.merge(opts)
159
159
  options[:raise_exception] = a.to_s.match(/\!$/)
160
160
  self.run_callbacks(action) do
@@ -1,5 +1,4 @@
1
1
  module SimpleModel
2
2
  class ActionError < StandardError; end
3
3
  class ValidationError < StandardError; end
4
- class ArgumentError < StandardError; end
5
4
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleModel
2
- VERSION = "1.2.5"
2
+ VERSION = "1.2.7"
3
3
  end
@@ -9,7 +9,7 @@ describe SimpleModel::Attributes do
9
9
  @init = TestInit.new(:test1 => "1", :test2 => '2')
10
10
  end
11
11
 
12
- it "should set provided attributes on initialize" do
12
+ it "should set provided attributes on initialize" do
13
13
  @init.test1.should eql("1")
14
14
  @init.test2.should eql("2")
15
15
  end
@@ -19,7 +19,51 @@ describe SimpleModel::Attributes do
19
19
  @init.attributes[:test1].should eql("1")
20
20
  @init.attributes[:test2].should eql("2")
21
21
  end
22
-
22
+
23
+ context '#before_initialize' do
24
+ before(:all) do
25
+ class TestInit
26
+ include SimpleModel::Attributes
27
+ # Do not initalize blank attributes
28
+ self.before_initialize = lambda {|obj,attrs| attrs.select{|k,v| !v.blank?}}
29
+ has_attribute :far
30
+ end
31
+ end
32
+
33
+ it "should raise an exception if we try to set to something other than a Proc" do
34
+ lambda {TestInit.before_initialize = "bad stuff"}.should raise_error
35
+ end
36
+
37
+ it "should run the supplied lambda" do
38
+ t = TestInit.new(:far => "")
39
+ t.initialized?(:far).should be_false
40
+ t = TestInit.new(:far => "t")
41
+ t.initialized?(:far).should be_true
42
+ end
43
+
44
+ end
45
+
46
+ context '#after_initialize' do
47
+ before(:all) do
48
+ class TestInit
49
+ include SimpleModel::Attributes
50
+ # Do not initalize blank attributes
51
+ self.after_initialize = lambda { |obj| obj.car = "test" if obj.car.blank?}
52
+ has_attribute :car
53
+ end
54
+ end
55
+
56
+ it "should raise an exception if we try to set to something other than a Proc" do
57
+ lambda {TestInit.after_initialize = "bad stuff"}.should raise_error
58
+ end
59
+
60
+ it "should run the supplied lambda" do
61
+ t = TestInit.new(:far => "")
62
+ t.car.should eql("test")
63
+ end
64
+
65
+ end
66
+
23
67
  context '#new_with_store'do
24
68
  it "should use the provided object as the attribute store" do
25
69
  my_store = {:test1 => 1,:test2 => 2}
@@ -29,7 +73,7 @@ describe SimpleModel::Attributes do
29
73
  my_store[:test1].should eql(new.test1)
30
74
  end
31
75
  end
32
-
76
+
33
77
  context "AVAILABLE_ATTRIBUTE_METHODS" do
34
78
  SimpleModel::Attributes::ClassMethods::AVAILABLE_ATTRIBUTE_METHODS.each do |m,options|
35
79
  it "should respond to #{m}" do
@@ -55,14 +99,14 @@ describe SimpleModel::Attributes do
55
99
  def default_value
56
100
  "bar"
57
101
  end
58
-
102
+
59
103
  def default_hop
60
104
  "hop" if nap
61
105
  end
62
106
  end
63
-
107
+
64
108
  end
65
-
109
+
66
110
  before(:each) do
67
111
  @default = TestDefault.new
68
112
  end
@@ -70,11 +114,11 @@ describe SimpleModel::Attributes do
70
114
  it "should define setter method" do
71
115
  @default.respond_to?(:foo=).should be_true
72
116
  end
73
-
117
+
74
118
  it "should define reader/getter method" do
75
119
  @default.respond_to?(:foo).should be_true
76
120
  end
77
-
121
+
78
122
  context ':initialize => false' do
79
123
  it "should not initialize with the default value" do
80
124
  @default.attributes[:tip].should be_nil
@@ -87,30 +131,30 @@ describe SimpleModel::Attributes do
87
131
  end
88
132
  end
89
133
  end
90
-
91
- it "should call the method it describe by the default value if it exists" do
134
+
135
+ it "should call the method it describe by the default value if it exists" do
92
136
  @default.attributes[:bar].should eql("bar")
93
137
  end
94
-
95
- it "should set the defaul to the supplied symbol, if the method does not exist" do
138
+
139
+ it "should set the defaul to the supplied symbol, if the method does not exist" do
96
140
  @default.attributes[:fab].should eql(:some_symbol)
97
141
  end
98
-
142
+
99
143
  it "should allow default value to be an empty array" do
100
144
  @default.my_array.should eql([])
101
145
  end
102
-
146
+
103
147
  it "should create a boolean? method for each attribute" do
104
148
  @default.respond_to?(:foo?).should be_true
105
149
  end
106
-
150
+
107
151
  it "should return !blank?" do
108
152
  @default.my_array.should eql([]) # blank array
109
153
  @default.my_array?.should be_false
110
154
  @default.my_array << 1
111
155
  @default.my_array?.should be_true
112
156
  end
113
-
157
+
114
158
  it "should not allow blank if set" do
115
159
  @default.foo.should eql("foo")
116
160
  @default.foo = ""
@@ -118,51 +162,61 @@ describe SimpleModel::Attributes do
118
162
  @default.foo = "not blank"
119
163
  @default.foo.should eql("not blank")
120
164
  end
121
-
165
+
122
166
  it "should try for the default if its blank on get" do
123
167
  @default.hop.blank?.should be_true
124
168
  @default.nap = "yep"
125
169
  @default.hop.should eql("hop")
126
170
  end
127
-
128
-
129
171
  end
130
-
172
+
173
+ context 'options with conditional' do
174
+ before(:all) do
175
+ class WithConditional
176
+ include SimpleModel::Attributes
177
+ has_date :my_date, :if => lambda {|obj,val| !val.blank?}
178
+ has_date :my_other_date, :unless => :blank
179
+ end
180
+ end
181
+ it "should not raise error" do
182
+ new = WithConditional.new(:my_date => nil)
183
+ new.initialized?(:my_date).should be_false
184
+ end
185
+
186
+ it "should call blank on val if :blank is supplied" do
187
+ new = WithConditional.new(:my_other_date => nil)
188
+ new.initialized?(:my_other_date).should be_false
189
+ end
190
+ end
191
+
131
192
  context "on get" do
132
193
  it "should perform on_get when set" do
133
194
  class OnGet
134
195
  include SimpleModel::Attributes
135
196
  has_attribute :foo, :on_get => lambda{|obj,attr| (attr.blank? ? obj.send(:foo_default) : attr)}
136
-
197
+
137
198
  def foo_default
138
199
  "test"
139
200
  end
140
201
  end
141
-
202
+
142
203
  new = OnGet.new
143
204
  new.foo.should eql("test")
144
205
  new.foo = "foo"
145
206
  new.foo.should eql("foo")
146
207
  end
147
208
  end
148
-
209
+
149
210
  context 'if supplied value can be cast' do
150
- it "should throw an exception" do
151
- class TestThrow
211
+ before(:all) do
212
+ class TestAlias
152
213
  include SimpleModel::Attributes
153
- has_booleans :boo
154
- end
155
-
156
- lambda{TestThrow.new(:boo => [])}.should raise_error(SimpleModel::ArgumentError)
214
+ has_attribute :foo, :default => "bar"
215
+ alias_attribute(:bar,:foo)
216
+ end
157
217
  end
158
218
  context '#alias_attribute' do
159
219
  it "should create alias for attribute" do
160
- class TestAlias
161
- include SimpleModel::Attributes
162
- has_attribute :foo, :default => "bar"
163
- alias_attribute(:bar,:foo)
164
- end
165
-
166
220
  t = TestAlias.new(:bar => "foo")
167
221
  t.bar.should eql("foo")
168
222
  t.foo.should eql('foo')
@@ -170,29 +224,49 @@ describe SimpleModel::Attributes do
170
224
  t.bar.should eql("foo")
171
225
  t.foo.should eql('foo')
172
226
  end
173
- end
227
+ end
174
228
  end
175
-
229
+
176
230
  context "regression tests" do
177
- it "should merge defined attributes when class are inhereted" do
231
+ before(:all) do
178
232
  class MyBase
179
233
  include SimpleModel::Attributes
180
234
  has_boolean :bar
235
+ has_attribute :str
236
+ has_dates :some, :thing, :default => :fetch_date, :allow_blank => false, :initialize => false
237
+
238
+ def fetch_date
239
+ Date.today
240
+ end
181
241
  end
182
-
242
+
183
243
  class NewerBase < MyBase
184
244
  has_boolean :foo
245
+ has_int :str
185
246
  end
186
-
247
+ end
248
+ it "should merge defined attributes when class are inhereted" do
187
249
  NewerBase.defined_attributes[:bar].blank?.should be_false
188
250
  n = NewerBase.new
189
251
  n.respond_to?(:bar_will_change!).should be_true
190
252
  end
253
+
254
+ it "should defaults that were not initialized should work from parent class" do
255
+ n = NewerBase.new
256
+ n.some.should eql(Date.today)
257
+ n.thing.should eql(Date.today)
258
+ end
259
+
260
+ it "should allow redefining methods in child classes" do
261
+ n = NewerBase.new
262
+ n.str = '1'
263
+ n.str.should eql(1)
264
+ end
191
265
  end
192
-
266
+
193
267
  after(:all) do
194
- [:TestThrow,:OnGet,:TestDefault,:TestInit,:MyBase,:NewerBase].each do |test_klass|
195
- Object.send(:remove_const,test_klass)
268
+ [:OnGet,:TestDefault,:TestInit,:MyBase,:NewerBase].each do |test_klass|
269
+ Object.send(:remove_const,test_klass) if defined?(test_klass)
196
270
  end
197
271
  end
198
- end
272
+ end
@@ -204,15 +204,18 @@ describe SimpleModel do
204
204
  before(:each) do
205
205
  class TestStuff < SimpleModel::Base
206
206
  has_attribute :bar
207
+ validates_presence_of :bar
207
208
  end
208
209
 
209
- class OtherStuff < SimpleModel::Base
210
- has_attribute :bar
211
- end
212
-
213
210
  class NewTestStuff < TestStuff
214
211
  has_boolean :foo
215
212
  end
213
+
214
+ class OtherStuff < NewTestStuff
215
+ has_attribute :other
216
+ validates_numericality_of :other
217
+ end
218
+
216
219
  end
217
220
  it "should merge defined attributes when class are inhereted" do
218
221
  NewTestStuff.defined_attributes[:bar].blank?.should be_false
@@ -225,8 +228,16 @@ describe SimpleModel do
225
228
  NewTestStuff.new.respond_to?(:bar_will_change!).should be_true
226
229
  NewTestStuff.new.respond_to?(:foo_will_change!).should be_true
227
230
  end
231
+
232
+ it "should not throw exception method missing" do
233
+ o = OtherStuff.new
234
+ lambda { o.valid? }.should_not raise_error
235
+ end
236
+
228
237
  after(:each) do
229
- Object.send(:remove_const,:NewTestStuff)
238
+ [:OtherStuff,:NewTestStuff].each do |con|
239
+ Object.send(:remove_const,con)
240
+ end
230
241
  end
231
242
  end
232
243
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
4
+ version: 1.2.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-22 00:00:00.000000000 Z
12
+ date: 2013-02-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  version: '0'
128
128
  requirements: []
129
129
  rubyforge_project: simple_model
130
- rubygems_version: 1.8.24
130
+ rubygems_version: 1.8.25
131
131
  signing_key:
132
132
  specification_version: 3
133
133
  summary: Simpifies building tableless models or models backed by webservices