simple_model 1.2.26 → 1.2.27

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NDZkZTQzYzExYjM5MWRiMzhmZjViZGRkYjA5NDQ1MjcxY2M1NDE4YQ==
4
+ NzIwOThmYzg1NGI0ZGZjN2YwNTdhZTU3NGM2YzNmMDBlMGJkMzA2NA==
5
5
  data.tar.gz: !binary |-
6
- ODU0YTMzMWM4OTA0NGRlYWVkM2U1YTA2MTJhY2Q4MTQxNzc5YTE1NQ==
6
+ YWEwNDJjZDg4ZjExOTYxODYyMmQ0NjljZjNkY2VkOTg3Y2Q1ZjI5Nw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZGM5YTJlY2I2NjU2Y2RkMmQ5MWY2MWJmNmMxNTQyOTdhZWQ1MzYxY2U0NGUy
10
- OTQzZWZmN2RkNjg5NWIzMzUzZGM0YzBhYTMxNjk3ZTBhYWRmNjVkZmQwYjcz
11
- YzFlY2VhZDE0ODM2YTExZmM0ODZlZDAyZTUzNzQ4OTc3MWQxYjU=
9
+ NDkyOTdlMDdmZTczMGI3MGQyZmZlNzliNDkzN2M2ZTY4NGU4MmNjNGZmZWI0
10
+ M2M3YmMzNWQ3Njg2ZjEwZWY4YTUzYzEwMjkwNDI2NTU5ZDc4MzdhNDdhZjYx
11
+ MzQ4OWRkZjY3MDczY2Q5Yzc4NTVjN2NiMjdiOWNlOGE4YzFlMGY=
12
12
  data.tar.gz: !binary |-
13
- NGViMDY2YzUwYzhlYzdiZWNiMDFkNjg4NmY2MmY0NTc3YzMxN2QzN2E2ODgx
14
- MDJlODJkM2VlMjkzYmY4MzJhNGQ4MzgyY2E4ZDZiYjcwZWU2Yzk3ZWIyOTFj
15
- ZmZlMDgzYWQ5MDExNWUxZDYwMDE5ZGMzZDNiMWM3MzI3Y2EzNDQ=
13
+ YzhiNmE4MWU5ZDVhOWYzZTZlZGUyNmI1MzU1YmQxODY5MjdkMGRhNjg2MTJk
14
+ MWJhZDNiNDQyY2E1YTg1NzlmM2FkODViMmNlZTRiYzhlMWEwOWVjMmRhZDZi
15
+ ZDBhMzAwODQzYjM1MTBiYWIxNWI2YjNjYzBlM2Y0MGZjYzYyODc=
@@ -1,40 +1,95 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'benchmark'
3
+ require 'simple_model'
4
+
1
5
  class BenchClass < SimpleModel::Base
6
+ has_attribute :foo
7
+ has_boolean :bool
2
8
  has_int :num
3
- has_date :date, :default => :today
9
+ has_date :date, :default => :today, :allow_blank => false
10
+ has_time :time, :allow_blank => true
11
+ has_float :float, :default => 0.0
4
12
  has_decimal :dec
5
13
 
6
14
  def today
7
15
  Date.today
8
16
  end
9
17
  end
10
- Benchmark.bm do |b|
11
- b.report("initialize") do
18
+
19
+ puts `ruby -v`
20
+ Benchmark.bmbm do |b|
21
+ b.report("init") do
12
22
  30000.times.each do
13
23
  BenchClass.new()
14
24
  end
15
25
  end
16
26
 
17
- b.report("initialize with attrs") do
27
+ b.report("init w/attrs") do
18
28
  30000.times.each do
19
- BenchClass.new(:num => 1, :dec => "12.4")
29
+ BenchClass.new(:foo => nil,
30
+ :bool => false,
31
+ :num => 1,
32
+ :dec => "12.4",
33
+ :time => Time.now,
34
+ :float => 1.0
35
+ )
20
36
  end
21
37
  end
22
38
 
23
39
  b.report("get") do
24
40
  30000.times.each do
25
- klass = BenchClass.new
26
- klass.num
27
- klass.dec
28
- klass.date
41
+ bc = BenchClass.new
42
+ bc.foo
43
+ bc.bool
44
+ bc.num
45
+ bc.dec
46
+ bc.date
47
+ bc.time
48
+ bc.float
49
+ end
50
+ end
51
+
52
+ b.report("get?") do
53
+ 30000.times.each do
54
+ bc = BenchClass.new
55
+ bc.foo?
56
+ bc.bool?
57
+ bc.num?
58
+ bc.dec?
59
+ bc.date?
60
+ bc.time?
61
+ bc.float?
29
62
  end
30
63
  end
31
64
 
32
65
  b.report("set") do
33
66
  30000.times.each do
34
- klass = BenchClass.new
35
- klass.num = 1
36
- klass.dec = '12.4'
37
- klass.date = "2014-12-25"
67
+ bc = BenchClass.new
68
+ bc.foo = nil
69
+ bc.bool = true
70
+ bc.num = 1
71
+ bc.dec = '12.4'
72
+ bc.date = "" # check blank
73
+ bc.time = Time.now
74
+ bc.float = 10.0
38
75
  end
39
76
  end
40
77
  end
78
+
79
+ # ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
80
+
81
+ # Rehearsal ------------------------------------------------
82
+ # init 1.360000 0.000000 1.360000 ( 1.364654)
83
+ # init w/attrs 2.510000 0.000000 2.510000 ( 2.512509)
84
+ # get 1.620000 0.000000 1.620000 ( 1.619021)
85
+ # get? 1.700000 0.000000 1.700000 ( 1.697857)
86
+ # set 2.720000 0.000000 2.720000 ( 2.724271)
87
+ # --------------------------------------- total: 9.910000sec
88
+
89
+ # user system total real
90
+ # init 1.350000 0.000000 1.350000 ( 1.352561)
91
+ # init w/attrs 2.530000 0.010000 2.540000 ( 2.532518)
92
+ # get 1.610000 0.000000 1.610000 ( 1.613509)
93
+ # get? 1.690000 0.000000 1.690000 ( 1.693701)
94
+ # set 2.700000 0.000000 2.700000 ( 2.698375)
95
+
data/gemfiles/4.2.gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem 'activesupport','~> 4.2.0.rc3'
4
- gem 'activemodel','~> 4.2.0.rc3'
3
+ gem 'activesupport','~> 4.2.0'
4
+ gem 'activemodel','~> 4.2.0'
5
5
 
6
6
  gemspec :path => "../"
@@ -3,8 +3,26 @@ module SimpleModel
3
3
  include ExtendCore
4
4
  extend ActiveSupport::Concern
5
5
  include ActiveModel::AttributeMethods
6
+ include ActiveModel::Dirty
7
+
8
+ DEFAULT_ATTRIBUTE_SETTINGS = {:attributes_method => :attributes,
9
+ :allow_blank => false,
10
+ :initialize => true
11
+ }.freeze
12
+
13
+ AVAILABLE_ATTRIBUTE_METHODS = {
14
+ :has_attribute => {:alias => :has_attributes, :options => {:allow_blank => true}},
15
+ :has_boolean => {:cast_to => :to_b, :alias => :has_booleans, :options => {:allow_blank => true, :boolean => true}},
16
+ :has_currency => {:cast_to => :to_d, :alias => :has_currencies},
17
+ :has_date => {:cast_to => :to_date, :alias => :has_dates} ,
18
+ :has_decimal => {:cast_to => :to_d, :alias => :has_decimals},
19
+ :has_float => {:cast_to => :to_f, :alias => :has_floats},
20
+ :has_int => {:cast_to => :to_i, :alias => :has_ints},
21
+ :has_time => {:cast_to => :to_time, :alias => :has_times}
22
+ }.freeze
23
+
6
24
  attr_accessor :attributes
7
-
25
+
8
26
  def initialize(*attrs)
9
27
  attrs = attrs.extract_options!
10
28
  attrs = attributes_for_init(attrs)
@@ -36,50 +54,68 @@ module SimpleModel
36
54
  end
37
55
  alias :set_attributes :set
38
56
 
39
- def set_attribute(attr,val)
40
- options = self.class.defined_attributes[attr] || {}
41
- if allow_attribute_action?(val,options)
42
- allow_blank = options[:allow_blank]
43
- default = options[:default]
44
- val = fetch_default_value(default) if (!allow_blank && default && val.blank?)
45
- unless (val.blank? && !allow_blank)
46
- val = options[:on_set].call(self,val) if options.key?(:on_set)
57
+ def set_attribute(attr,val,opts=nil)
58
+ opts ||= fetch_attribute_options(attr)
59
+ if allow_attribute_action?(val,opts)
60
+ allow_blank = opts[:allow_blank]
61
+ val = fetch_default_value(opts[:default]) unless skip_set_default?(attr,opts,val)
62
+ unless (opts[:boolean] ? (!allow_blank && val.blank? && (val != false)) : (!allow_blank && val.blank?))
63
+ val = opts[:on_set].call(self,val) if opts.key?(:on_set)
47
64
  send("#{attr}_will_change!") if (initialized?(attr) && val != attributes[attr])
48
65
  attributes[attr] = val
49
- options[:after_set].call(self,val) if options[:after_set]
66
+ opts[:after_set].call(self,val) if opts[:after_set]
50
67
  end
51
68
  end
52
69
  end
53
70
 
54
- def get_attribute(attr)
71
+ def get_attribute(attr,opts=nil)
72
+ opts ||= fetch_attribute_options(attr)
55
73
  val = attributes[attr]
56
- options = self.class.defined_attributes[attr] || {}
57
- if (options.key?(:default) && (!initialized?(attr) || (!options[:allow_blank] && val.blank?)))
58
- val = attributes[attr] = fetch_default_value(options[:default])
59
- end
60
- if options[:on_get]
61
- options[:on_get].call(self,val)
74
+ val = attributes[attr] ||= fetch_default_value(opts[:default]) unless skip_get_default?(attr,opts,val)
75
+ if opts[:on_get]
76
+ opts[:on_get].call(self,val)
62
77
  else
63
78
  val
64
79
  end
65
80
  end
66
81
 
82
+ def fetch_attribute_options(attr)
83
+ self.class.defined_attributes[attr] || {}
84
+ end
85
+
67
86
  def get_attribute?(attr)
68
- return false unless val = get_attribute(attr)
87
+ return false unless val = send(attr)
69
88
  if val.respond_to?(:blank?)
70
89
  return !val.blank?
71
- elsif val.respond_to?(:to_b)
90
+ elsif val.respond_to?(:to_b)
72
91
  return val.to_b
73
92
  end
74
93
  !val.nil?
75
94
  end
76
95
 
77
- private
78
-
79
96
  def attribute_defined?(attr)
80
97
  self.class.attribute_defined?(attr)
81
98
  end
82
99
 
100
+ # Rails 3.2 + required when searching for attributes in from inherited classes/models
101
+ def attribute(attr)
102
+ get_attribute(attr)
103
+ end
104
+
105
+ private
106
+
107
+ def skip_get_default?(attr,opts,val)
108
+ (val || !opts.key?(:default) || (opts[:boolean] && (val == false)))
109
+ end
110
+
111
+ def skip_set_default?(attr,opts,val)
112
+ return true if (!opts.key?(:default) ||
113
+ initialized?(attr) ||
114
+ (opts[:boolean] && (val == false)))
115
+ blnk = val.blank?
116
+ (!blnk || (blnk && opts[:allow_blank]))
117
+ end
118
+
83
119
  def fetch_default_value(arg)
84
120
  return send(arg) if (arg.is_a?(Symbol) && self.respond_to?(arg))
85
121
  arg
@@ -104,57 +140,40 @@ module SimpleModel
104
140
  end
105
141
 
106
142
  def attributes_have_alias?(attrs,attr)
107
- !(self.class.alias_attributes.select{ |a, m| (m == attr.to_sym && attrs.key?(a)) }).empty?
143
+ base_meth = self.class.alias_attributes.rassoc(attr.to_sym)
144
+ base_meth && attrs.key?(base_meth[0])
145
+ #!(self.class.alias_attributes.select{ |a, m| (m == attr.to_sym && attrs.key?(a)) }).empty?
108
146
  end
109
147
 
110
148
  def allow_attribute_action?(val,options)
111
149
  return true unless (options[:if] || options[:unless])
112
150
  b = true
113
- opt = options[:if]
114
- if opt.is_a?(Symbol)
115
- if opt == :blank
116
- b = val.blank?
117
- else
118
- b = send(opt)
151
+ if opt = options[:if]
152
+ if opt.is_a?(Symbol)
153
+ if opt == :blank
154
+ b = val.blank?
155
+ else
156
+ b = send(opt)
157
+ end
158
+ elsif opt.is_a?(Proc)
159
+ b = opt.call(self,val)
119
160
  end
120
- elsif opt.is_a?(Proc)
121
- b = opt.call(self,val)
122
161
  end
123
- opt = options[:unless]
124
- if opt.is_a?(Symbol)
125
- if opt == :blank
126
- b = !val.blank?
127
- else
128
- b = !send(opt)
162
+ if opt = options[:unless]
163
+ if opt.is_a?(Symbol)
164
+ if opt == :blank
165
+ b = !val.blank?
166
+ else
167
+ b = !send(opt)
168
+ end
169
+ elsif opt.is_a?(Proc)
170
+ b = !opt.call(self,val)
129
171
  end
130
- elsif opt.is_a?(Proc)
131
- b = !opt.call(self,val)
132
172
  end
133
173
  b
134
174
  end
135
175
 
136
- # Rails 3.2 + required when searching for attributes in from inherited classes/models
137
- def attribute(attr)
138
- get_attribute(attr)
139
- end
140
-
141
176
  module ClassMethods
142
- DEFAULT_ATTRIBUTE_SETTINGS = {:attributes_method => :attributes,
143
- :allow_blank => false,
144
- :initialize => true
145
- }.freeze
146
-
147
- AVAILABLE_ATTRIBUTE_METHODS = {
148
- :has_attribute => {:alias => :has_attributes, :options => {:allow_blank => true}},
149
- :has_boolean => {:cast_to => :to_b, :alias => :has_booleans, :options => {:allow_blank => true}},
150
- :has_currency => {:cast_to => :to_d, :alias => :has_currencies},
151
- :has_date => {:cast_to => :to_date, :alias => :has_dates} ,
152
- :has_decimal => {:cast_to => :to_d, :alias => :has_decimals},
153
- :has_float => {:cast_to => :to_f, :alias => :has_floats},
154
- :has_int => {:cast_to => :to_i, :alias => :has_ints},
155
- :has_time => {:cast_to => :to_time, :alias => :has_times}
156
- }.freeze
157
-
158
177
  AVAILABLE_ATTRIBUTE_METHODS.each do |method,method_options|
159
178
  define_method(method) do |*attributes|
160
179
  options = attributes.extract_options!
@@ -163,7 +182,7 @@ module SimpleModel
163
182
  options[:on_set] = lambda {|obj,val| val.send(method_options[:cast_to]) } if method_options[:cast_to]
164
183
  create_attribute_methods(attributes,options)
165
184
  end
166
- module_eval("alias #{method_options[:alias]} #{method}")
185
+ module_eval("alias #{method_options[:alias]} #{method}") if method_options[:alias]
167
186
  end
168
187
 
169
188
  # Creates a new instance where the attributes store is set to object
@@ -251,7 +270,7 @@ module SimpleModel
251
270
 
252
271
  def define_reader_with_options(attr,options)
253
272
  define_method(attr) do
254
- get_attribute(attr)
273
+ get_attribute(attr,options)
255
274
  end
256
275
  define_method("#{attr}?") do
257
276
  get_attribute?(attr)
@@ -263,14 +282,14 @@ module SimpleModel
263
282
  # initialized.
264
283
  def define_setter_with_options(attr,options)
265
284
  define_method("#{attr}=") do |val|
266
- set_attribute(attr,val)
285
+ set_attribute(attr,val,options)
267
286
  end
268
287
  end
269
288
 
270
289
  # Creates alias setter and getter for the supplied attribute using the supplied alias
271
290
  # See spec for example.
272
291
  def alias_attribute(new_alias,attr)
273
-
292
+
274
293
  # get to the base attribute
275
294
  while alias_attributes[attr]
276
295
  attr = alias_attributes[attr]
@@ -331,7 +350,7 @@ module SimpleModel
331
350
  base.alias_attributes = alias_attributes.merge(base.alias_attributes)
332
351
  super
333
352
  # Rails 3.0 Hack
334
- if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
353
+ if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR < 1)
335
354
  base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
336
355
  base.attribute_method_affix :prefix => 'reset_', :suffix => '!'
337
356
  end
@@ -343,7 +362,6 @@ module SimpleModel
343
362
  # ActiveModel::Dirty included
344
363
  def self.included(base)
345
364
  base.extend(Attributes::ClassMethods)
346
- base.send(:include, ActiveModel::Dirty)
347
365
  base.send(:include, ActiveModel::Validations)
348
366
  base.send(:include, ActiveModel::Conversion)
349
367
  base.extend ActiveModel::Naming
@@ -351,7 +369,7 @@ module SimpleModel
351
369
  base.send(:include, ActiveModel::Validations::Callbacks)
352
370
 
353
371
  # Rails 3.0 Hack
354
- if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR == 0)
372
+ if (ActiveModel::VERSION::MAJOR == 3 && ActiveModel::VERSION::MINOR < 1)
355
373
  base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
356
374
  base.attribute_method_affix :prefix => 'reset_', :suffix => '!'
357
375
  end
@@ -1,7 +1,7 @@
1
1
  module SimpleModel
2
2
  module ToCurrencyS
3
3
  def to_currency_s(symbol='$',rnd=2)
4
- cs = self.round(rnd).abs.to_s
4
+ cs = (rnd ? self.round(rnd) : self).abs.to_s
5
5
  while cs.index('.') != (cs.length-3)
6
6
  cs << '0'
7
7
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleModel
2
- VERSION = "1.2.26"
2
+ VERSION = "1.2.27"
3
3
  end
@@ -1,335 +1,503 @@
1
1
  require 'spec_helper.rb'
2
2
 
3
+ class AttributesTest
4
+ include SimpleModel::Attributes
5
+ end
6
+
3
7
  describe SimpleModel::Attributes do
4
- before(:all) do
5
- class TestInit
8
+
9
+ # We need a clean class for each spec
10
+ around(:each) do |example|
11
+ class AttributesTest
6
12
  include SimpleModel::Attributes
7
- has_attributes :test1,:test2
8
13
  end
9
- @init = TestInit.new(:test1 => "1", :test2 => '2')
10
- end
11
14
 
12
- it "should set provided attributes on initialize" do
13
- @init.test1.should eql("1")
14
- @init.test2.should eql("2")
15
- end
15
+ example.run
16
16
 
17
- it "should include set attributes in attributes hash" do
18
- @init.attributes.should be_kind_of(ActiveSupport::HashWithIndifferentAccess)
19
- @init.attributes[:test1].should eql("1")
20
- @init.attributes[:test2].should eql("2")
17
+ Object.send(:remove_const,:AttributesTest) if defined?(:AttributesTest)
21
18
  end
22
19
 
23
- context '#before_initialize' do
24
- before(:all) do
25
- class TestInit
26
- include SimpleModel::Attributes
27
- # Do not initialize blank attributes
28
- self.before_initialize = lambda {|obj,attrs| attrs.select{|k,v| !v.blank?}}
29
- has_attribute :far
30
- end
31
- end
20
+ context "class methods" do
32
21
 
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
22
+ describe '#create_attribute_methods' do
23
+ context "no options" do
24
+ before(:each) do
25
+ AttributesTest.create_attribute_methods([:has_foo],{})
26
+ end
36
27
 
37
- it "should run the supplied lambda" do
38
- t = TestInit.new(:far => "")
39
- t.initialized?(:far).should eql(false)
40
- t = TestInit.new(:far => "t")
41
- t.initialized?(:far).should eql(true)
42
- end
28
+ let(:attributes_test) { AttributesTest.new() }
43
29
 
44
- end
30
+ it {expect(attributes_test).to respond_to(:has_foo)}
31
+ it {expect(attributes_test).to respond_to(:has_foo=)}
32
+ it {expect(attributes_test).to respond_to(:has_foo?)}
33
+ it "should set the value" do
34
+ expect(attributes_test.has_foo = "test").to eql("test")
35
+ end
45
36
 
46
- context '#after_initialize' do
47
- before(:all) do
48
- class TestInit
49
- include SimpleModel::Attributes
50
- # Do not initialize blank attributes
51
- self.after_initialize = lambda { |obj| obj.car = "test" if obj.car.blank?}
52
- has_attribute :car
37
+ it "should get the value" do
38
+ attributes_test.has_foo = "test"
39
+ expect(attributes_test.has_foo).to eql("test")
40
+ end
41
+
42
+ it "should get? boolean value" do
43
+ expect(attributes_test).to_not be_has_foo
44
+ attributes_test.has_foo = "test"
45
+ expect(attributes_test).to be_has_foo
46
+ end
53
47
  end
54
- end
55
48
 
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
49
+ context "options set" do
59
50
 
60
- it "should run the supplied lambda" do
61
- t = TestInit.new(:far => "")
62
- t.car.should eql("test")
63
- end
51
+ context "with default" do
64
52
 
65
- end
53
+ context "with initialize == true" do
54
+ before(:each) do
55
+ AttributesTest.create_attribute_methods([:with_default], {:default => "foo", :initialize => true})
56
+ end
66
57
 
67
- context '#new_with_store'do
68
- it "should use the provided object as the attribute store" do
69
- my_store = {:test1 => 1,:test2 => 2}
70
- nw = TestInit.new_with_store(my_store)
71
- nw.test1 = 3
72
- nw.test1.should eql(3)
73
- my_store[:test1].should eql(nw.test1)
74
- end
75
- end
58
+ let(:attributes_test) { AttributesTest.new() }
76
59
 
77
- context "AVAILABLE_ATTRIBUTE_METHODS" do
78
- SimpleModel::Attributes::ClassMethods::AVAILABLE_ATTRIBUTE_METHODS.each do |m,options|
79
- it "should respond to #{m}" do
80
- TestInit.respond_to?(m).should eql(true)
81
- end
82
- it "should respond to alias #{options[:alias]}" do
83
- TestInit.respond_to?(options[:alias]).should eql(true)
84
- end
85
- end
86
- end
60
+ it "should work" do
61
+ expect(attributes_test.attributes[:with_default]).to eql('foo')
62
+ end
63
+
64
+ end
65
+
66
+ context "with initialize == false" do
67
+ before(:each) do
68
+ AttributesTest.create_attribute_methods([:with_default_no_init], {:default => "foo", :initialize => false})
69
+ end
70
+
71
+ let(:attributes_test) { AttributesTest.new() }
72
+
73
+ it "should work" do
74
+ expect(attributes_test.attributes).to_not have_key(:with_default_no_init)
75
+ end
76
+
77
+ it "should set on get" do
78
+ expect(attributes_test.with_default_no_init).to eql('foo')
79
+ end
80
+ end
81
+
82
+ context "set to a symbol for a method" do
83
+ before(:each) do
84
+ AttributesTest.send(:define_method, :default_method) do
85
+ Date.today
86
+ end
87
+
88
+ AttributesTest.create_attribute_methods([:with_default_method], {:default => :default_method})
89
+ end
90
+ let(:attributes_test) { AttributesTest.new() }
91
+
92
+ it { expect(attributes_test.with_default_method).to eql(Date.today) }
93
+ end
87
94
 
88
- context '#has_attribute' do
89
- before(:all) do
90
- class TestDefault
91
- include SimpleModel::Attributes
92
- has_attribute :foo, :default => "foo", :allow_blank => false
93
- has_attribute :bar, :default => :default_value
94
- has_attribute :fab, :default => :some_symbol
95
- has_attribute :hop, :default => :default_hop, :allow_blank => false
96
- has_attribute :tip, :default => "2", :initialize => false, :allow_blank => false
97
- has_attribute :nap
98
- has_attribute :my_array, :default => []
99
- def default_value
100
- "bar"
95
+ context "set to a non-method symbol" do
96
+ before(:each) do
97
+ AttributesTest.create_attribute_methods([:with_default_sym], {:default => :_foo})
98
+ end
99
+
100
+ let(:attributes_test) { AttributesTest.new() }
101
+
102
+ it { expect(attributes_test.with_default_sym).to eql(:_foo) }
103
+ end
104
+ end
105
+
106
+ context "with on_set" do
107
+ before(:each) do
108
+ AttributesTest.create_attribute_methods([:with_on_set], {:on_set => lambda {|obj,val| val.to_i } })
109
+ end
110
+
111
+ let(:attributes_test) { AttributesTest.new(:with_on_set => "1") }
112
+
113
+ it {expect(attributes_test.with_on_set).to eql(1)}
114
+ end
115
+
116
+ context "with allow_blank == false" do
117
+ before(:each) do
118
+ AttributesTest.create_attribute_methods([:prevent_blank], {:allow_blank => false})
119
+ end
120
+
121
+ let(:attributes_test) { AttributesTest.new(:prevent_blank => "") }
122
+
123
+ it "should not initialize" do
124
+ expect(attributes_test.attributes).to_not have_key(:prevent_blank)
125
+ end
126
+
127
+ it "should allow setting with non-blank value" do
128
+ attributes_test.prevent_blank = "not blank"
129
+ expect(attributes_test.prevent_blank).to eql("not blank")
130
+ attributes_test.prevent_blank = nil
131
+ expect(attributes_test.prevent_blank).to eql("not blank")
132
+ attributes_test.prevent_blank = 1
133
+ expect(attributes_test.prevent_blank).to eql(1)
134
+ end
135
+ end
136
+
137
+ context "with allow_blank == false and boolean == true" do
138
+ before(:each) do
139
+ AttributesTest.create_attribute_methods([:allow_false_boolean], {:allow_blank => false, :boolean => true})
140
+ end
141
+ let(:attributes_test) { AttributesTest.new(:allow_false_boolean => "") }
142
+
143
+ it "should not initialize" do
144
+ expect(attributes_test.attributes).to_not have_key(:allow_false_boolean)
145
+ end
146
+
147
+ it "should allow setting with non-blank value" do
148
+ attributes_test.allow_false_boolean = 1
149
+ expect(attributes_test.allow_false_boolean).to eql(1)
150
+ attributes_test.allow_false_boolean = nil
151
+ expect(attributes_test.allow_false_boolean).to eql(1)
152
+ attributes_test.allow_false_boolean = false
153
+ expect(attributes_test.allow_false_boolean).to eql(false)
154
+ end
101
155
  end
102
156
 
103
- def default_hop
104
- "hop" if nap
157
+ context "with :if" do
158
+ context "set to a proc" do
159
+ before(:each) do
160
+ AttributesTest.has_date :if_proc, :if => lambda {|obj,val| !val.blank?}
161
+ end
162
+
163
+ it {expect(AttributesTest.new(:if_proc => nil)).to_not be_initialized(:if_proc)}
164
+
165
+ it {expect(AttributesTest.new(:if_proc => "2014-05-01")).to be_initialized(:if_proc)}
166
+ end
167
+
168
+ context "set to a :blank" do
169
+ before(:each) do
170
+ AttributesTest.has_attribute :if_blank, :if => :blank
171
+ end
172
+ it "init" do
173
+ init = AttributesTest.new(:if_blank => "")
174
+ expect(init).to be_initialized(:if_blank)
175
+
176
+ end
177
+ it {expect(AttributesTest.new(:if_blank => nil)).to be_initialized(:if_blank)}
178
+ it {expect(AttributesTest.new(:if_blank => "foo")).to_not be_initialized(:if_blank)}
179
+
180
+ end
181
+
182
+ context "set to a symbol" do
183
+ before(:each) do
184
+ AttributesTest.has_attribute :if_attr_1, :if => :if_true
185
+ AttributesTest.has_attribute :if_attr_2, :if => :if_false
186
+
187
+ AttributesTest.send :define_method, :if_true do
188
+ true
189
+ end
190
+
191
+ AttributesTest.send :define_method, :if_false do
192
+ false
193
+ end
194
+ end
195
+
196
+ let(:attributes_test) { AttributesTest.new(:if_attr_1 => "test", :if_attr_2 => "test" ) }
197
+ it {expect(attributes_test).to be_initialized(:if_attr_1)}
198
+ it {expect(attributes_test).to_not be_initialized(:if_attr_2)}
199
+ end
105
200
  end
201
+
202
+ context "with :unless" do
203
+ context "set to a proc" do
204
+ before(:each) do
205
+ AttributesTest.has_date :unless_proc, :unless => lambda {|obj,val| val.blank?}
206
+ end
207
+
208
+ it {expect(AttributesTest.new(:unless_proc => nil)).to_not be_initialized(:unless_proc)}
209
+
210
+ it {expect(AttributesTest.new(:unless_proc => "2014-05-01")).to be_initialized(:unless_proc)}
211
+ end
212
+
213
+ context "set to a :blank" do
214
+ before(:each) do
215
+ AttributesTest.has_attribute :unless_blank, :unless => :blank
216
+ end
217
+
218
+ it {expect(AttributesTest.new(:unless_blank => "")).to_not be_initialized(:unless_blank)}
219
+ it {expect(AttributesTest.new(:unless_blank => nil)).to_not be_initialized(:unless_blank)}
220
+ it {expect(AttributesTest.new(:unless_blank => "foo")).to be_initialized(:unless_blank)}
221
+
222
+ end
223
+
224
+ context "set to a symbol" do
225
+ before(:each) do
226
+ AttributesTest.has_attribute :unless_attr_1, :unless => :unless_true
227
+ AttributesTest.has_attribute :unless_attr_2, :unless => :unless_false
228
+
229
+ AttributesTest.send :define_method, :unless_true do
230
+ true
231
+ end
232
+
233
+ AttributesTest.send :define_method, :unless_false do
234
+ false
235
+ end
236
+ end
237
+
238
+ let(:attributes_test) { AttributesTest.new(:unless_attr_1 => "test", :unless_attr_2 => "test" ) }
239
+ it {expect(attributes_test).to_not be_initialized(:unless_attr_1)}
240
+ it {expect(attributes_test).to be_initialized(:unless_attr_2)}
241
+ end
242
+ end
243
+ end # end with options
244
+ end # end #create_attribute_methods
245
+
246
+ describe '#has_attribute' do
247
+ it {expect(AttributesTest).to respond_to(:has_attribute)}
248
+
249
+ before(:each) do
250
+ AttributesTest.has_attribute(:test_attr)
106
251
  end
107
252
 
108
- end
253
+ let(:attributes_test) { AttributesTest.new() }
109
254
 
110
- before(:each) do
111
- @default = TestDefault.new
112
- end
255
+ it {expect(attributes_test).to respond_to(:test_attr)}
113
256
 
114
- it "should define setter method" do
115
- @default.respond_to?(:foo=).should eql(true)
116
257
  end
117
258
 
118
- it "should define reader/getter method" do
119
- @default.respond_to?(:foo).should eql(true)
120
- end
259
+ describe '#has_boolean' do
260
+ it {expect(AttributesTest).to respond_to(:has_boolean)}
121
261
 
122
- context ':initialize => false' do
123
- it "should not initialize with the default value" do
124
- @default.attributes[:tip].should be_nil
125
- @default.tip.should eql("2")
262
+ before(:each) do
263
+ AttributesTest.has_boolean(:test_bool)
126
264
  end
127
- context "allow_blank => false"do
128
- it "should not initialize, but should set the value on get" do
129
- @default.attributes[:tip].should be_nil
130
- @default.tip.should eql("2")
131
- end
265
+ let(:attributes_test) { AttributesTest.new() }
266
+
267
+ it {expect(attributes_test).to respond_to(:test_bool)}
268
+
269
+ it "should cast to a boolean" do
270
+ attributes_test.test_bool = "false"
271
+ expect(attributes_test.test_bool).to eql(false)
272
+
273
+ attributes_test.test_bool = "true"
274
+ expect(attributes_test.test_bool).to eql(true)
132
275
  end
133
276
  end
134
277
 
135
- it "should call the method it describe by the default value if it exists" do
136
- @default.attributes[:bar].should eql("bar")
137
- end
278
+ describe '#has_date' do
279
+ it {expect(AttributesTest).to respond_to(:has_date)}
138
280
 
139
- it "should set the default to the supplied symbol, if the method does not exist" do
140
- @default.attributes[:fab].should eql(:some_symbol)
141
- end
281
+ before(:each) do
282
+ AttributesTest.has_date(:test_date)
283
+ end
142
284
 
143
- it "should allow default value to be an empty array" do
144
- @default.my_array.should eql([])
145
- end
285
+ let(:attributes_test) { AttributesTest.new() }
146
286
 
147
- it "should create a boolean? method for each attribute" do
148
- @default.respond_to?(:foo?).should eql(true)
149
- end
287
+ it {expect(attributes_test).to respond_to(:test_date)}
150
288
 
151
- it "should return !blank?" do
152
- @default.my_array.should eql([]) # blank array
153
- @default.my_array?.should eql(false)
154
- @default.my_array << 1
155
- @default.my_array?.should eql(true)
289
+ it "should cast to a date" do
290
+ attributes_test.test_date = "2014-12-22"
291
+ expect(attributes_test.test_date).to be_a(Date)
292
+ end
156
293
  end
157
294
 
158
- it "should not allow blank if set" do
159
- @default.foo.should eql("foo")
160
- @default.foo = ""
161
- @default.foo.should eql("foo")
162
- @default.foo = "not blank"
163
- @default.foo.should eql("not blank")
164
- end
295
+ describe '#has_decimal' do
296
+ it {expect(AttributesTest).to respond_to(:has_decimal)}
297
+
298
+ before(:each) do
299
+ AttributesTest.has_decimal(:test_deci)
300
+ end
165
301
 
166
- it "should try for the default if its blank on get" do
167
- @default.hop.blank?.should eql(true)
168
- @default.nap = "yep"
169
- @default.hop.should eql("hop")
302
+ let(:attributes_test) { AttributesTest.new() }
303
+
304
+ it {expect(attributes_test).to respond_to(:test_deci)}
305
+
306
+ it "should cast to a decimal" do
307
+ attributes_test.test_deci = "1.0"
308
+ expect(attributes_test.test_deci).to be_a(BigDecimal)
309
+ end
170
310
  end
171
- end
172
311
 
173
- context 'number and date/time attributes' do
174
- before(:all) do
175
- class NumDateTime
176
- include SimpleModel::Attributes
177
- has_date :my_date
178
- has_time :my_time
179
- has_int :my_int
180
- has_int :blank_int, :allow_blank => true
181
- has_decimal :my_decimal
182
- has_decimal :blank_decimal, :allow_blank => true
183
- has_float :my_float
184
- has_attribute :my_attr
185
- has_boolean :my_boolean
312
+ describe '#has_float' do
313
+ it {expect(AttributesTest).to respond_to(:has_float)}
314
+
315
+ before(:each) do
316
+ AttributesTest.has_float(:test_float)
317
+ end
318
+
319
+ let(:attributes_test) { AttributesTest.new() }
320
+
321
+ it {expect(attributes_test).to respond_to(:test_float)}
322
+
323
+ it "should cast to a float" do
324
+ attributes_test.test_float = "1.0"
325
+ expect(attributes_test.test_float).to be_a(Float)
186
326
  end
187
327
  end
188
- context "default options for number attributes" do
189
- context "set with blank value" do
190
- it "should not initialize" do
191
- num_date_time = NumDateTime.new(:my_date => nil, :my_time => "", :my_int => " ", :my_decimal => nil, :my_float => '')
192
- expect(num_date_time.initialized?(:my_date)).to eql(false)
193
- expect(num_date_time.initialized?(:my_time)).to eql(false)
194
- expect(num_date_time.initialized?(:my_int)).to eql(false)
195
- expect(num_date_time.initialized?(:my_decimal)).to eql(false)
196
- expect(num_date_time.initialized?(:my_float)).to eql(false)
197
- end
328
+
329
+ describe '#has_int' do
330
+ it {expect(AttributesTest).to respond_to(:has_int)}
331
+
332
+ before(:each) do
333
+ AttributesTest.has_int(:test_int)
198
334
  end
199
- context "override to allow_blank" do
200
- it "should not initialize" do
201
- num_date_time = NumDateTime.new(:blank_int => nil, :blank_decimal => "")
202
- expect(num_date_time.initialized?(:blank_int)).to eql(true)
203
- expect(num_date_time.initialized?(:blank_decimal)).to eql(true)
204
- end
335
+
336
+ let(:attributes_test) { AttributesTest.new() }
337
+
338
+ it {expect(attributes_test).to respond_to(:test_int)}
339
+
340
+ it "should cast to a float" do
341
+ attributes_test.test_int = "1"
342
+ expect(attributes_test.test_int).to be_a(Fixnum)
205
343
  end
206
344
  end
207
345
 
208
- context "set with blank value" do
209
- it "should not initialize" do
210
- num_date_time = NumDateTime.new(:my_attr => nil, :my_boolean => "")
211
- expect(num_date_time.initialized?(:my_attr)).to eql(true)
212
- expect(num_date_time.initialized?(:my_boolean)).to eql(true)
346
+ describe '#has_time' do
347
+ it {expect(AttributesTest).to respond_to(:has_time)}
348
+
349
+ before(:each) do
350
+ AttributesTest.has_time(:test_time)
351
+ end
352
+
353
+ let(:attributes_test) { AttributesTest.new() }
354
+
355
+ it {expect(attributes_test).to respond_to(:test_time)}
356
+
357
+ it "should cast to a date" do
358
+ attributes_test.test_time = "2014-12-22"
359
+ expect(attributes_test.test_time).to be_a(Time)
213
360
  end
214
361
  end
215
- end
216
362
 
217
- context 'options with conditional' do
218
- before(:all) do
219
- class WithConditional
220
- include SimpleModel::Attributes
221
- has_date :my_date, :if => lambda {|obj,val| !val.blank?}
222
- has_date :my_other_date, :unless => :blank
363
+ describe '#alias_attribute' do
364
+ before(:each) do
365
+ AttributesTest.has_attribute :base_foo
366
+ AttributesTest.alias_attribute :alias_foo, :base_foo
367
+ end
368
+
369
+ context "attribute is not defined" do
370
+ it { expect {AttributesTest.alias_attribute :alias_foo, :nope}.to raise_error(SimpleModel::UndefinedAttribute) }
371
+ end
372
+
373
+ it "should work" do
374
+ test_alias = AttributesTest.new(:alias_foo => "foo")
375
+ expect(test_alias.alias_foo).to eql("foo")
376
+ expect(test_alias.base_foo).to eql("foo")
223
377
  end
224
378
  end
225
- it "should not raise error" do
226
- new = WithConditional.new(:my_date => nil)
227
- new.initialized?(:my_date).should eql(false)
379
+
380
+ end # end class methods
381
+
382
+
383
+
384
+ context "initializing" do
385
+
386
+ before(:each) do
387
+ AttributesTest.has_attributes :test1,:test2
228
388
  end
229
389
 
230
- it "should call blank on val if :blank is supplied" do
231
- new = WithConditional.new(:my_other_date => nil)
232
- new.initialized?(:my_other_date).should eql(false)
390
+ let(:init_test) { AttributesTest.new(:test1 => '1', :test2 => '2') }
391
+
392
+
393
+ it { expect(init_test.test1).to eql('1') }
394
+ it { expect(init_test.test2).to eql('2') }
395
+
396
+ describe '#attributes' do
397
+ it { expect(init_test).to respond_to(:attributes) }
398
+ it { expect(init_test.attributes).to be_a(HashWithIndifferentAccess)}
233
399
  end
234
- end
235
400
 
236
- context "on get" do
237
- it "should perform on_get when set" do
238
- class OnGet
239
- include SimpleModel::Attributes
240
- has_attribute :foo, :on_get => lambda{|obj,attr| (attr.blank? ? obj.send(:foo_default) : attr)}
241
401
 
242
- def foo_default
243
- "test"
244
- end
402
+
403
+ describe '#before_initialize' do
404
+
405
+ context "before_initialize is not a Proc" do
406
+ it { expect {AttributesTest.before_initialize = "bad stuff"}.to raise_error }
245
407
  end
246
408
 
247
- new = OnGet.new
248
- new.foo.should eql("test")
249
- new.foo = "foo"
250
- new.foo.should eql("foo")
251
- end
252
- end
409
+ before(:each) do
410
+ # Do not initialize blank attributes
411
+ AttributesTest.before_initialize = lambda {|obj,attrs| attrs.select{|k,v| !v.blank?}}
412
+ AttributesTest.has_attribute :before_init
413
+ end
253
414
 
254
- context 'if supplied value can be cast' do
255
- before(:all) do
256
- class TestAlias
257
- include SimpleModel::Attributes
258
- has_attribute :foo, :default => "bar"
259
- alias_attribute(:bar,:foo)
415
+ it "should work" do
416
+ expect(AttributesTest.new(:before_init => "")).to_not be_initialized(:before_init)
417
+ expect(AttributesTest.new(:before_init => "t")).to be_initialized(:before_init)
260
418
  end
419
+
261
420
  end
262
- context '#alias_attribute' do
263
- it "should create alias for attribute" do
264
- t = TestAlias.new(:bar => "foo")
265
- t.bar.should eql("foo")
266
- t.foo.should eql('foo')
267
- t = TestAlias.new(:foo => "foo")
268
- t.bar.should eql("foo")
269
- t.foo.should eql('foo')
421
+
422
+ describe '#after_initialize' do
423
+
424
+ context "before_initialize is not a Proc" do
425
+ it { expect {AttributesTest.after_initialize = "bad stuff"}.to raise_error }
270
426
  end
271
- end
272
- end
273
427
 
274
- context "regression tests" do
275
- before(:all) do
276
- class MyBase
277
- include SimpleModel::Attributes
278
- has_boolean :bar
279
- has_attribute :str, :stuff
280
- has_currency :amount, :default => BigDecimal("0.0"), :initialize => false
281
- has_dates :some, :thing, :default => :fetch_date, :allow_blank => false, :initialize => false
282
- alias_attribute :other, :bar
283
- alias_attribute :other_amount, :amount
284
-
285
- def fetch_date
286
- Date.today
287
- end
428
+ before(:each) do
429
+ # Do not initialize blank attributes
430
+ AttributesTest.after_initialize = lambda { |obj| obj.after_init = "test" if obj.after_init.blank?}
431
+ AttributesTest.has_attribute :after_init
288
432
  end
289
433
 
290
- class NewerBase < MyBase
291
- has_boolean :foo
292
- has_int :str
434
+ it "should work" do
435
+ expect(AttributesTest.new(:after_init => "").after_init).to eql("test")
293
436
  end
294
437
 
295
- class NewestBase < NewerBase
296
- alias_attribute :some_amount, :other_amount
438
+ end
439
+
440
+ describe '#new_with_store'do
441
+ it "should work" do
442
+ my_store = {:test1 => 1,:test2 => 2}
443
+ nw = AttributesTest.new_with_store(my_store)
444
+ expect(AttributesTest.new_with_store(my_store).attributes.object_id).to eql(my_store.object_id)
297
445
  end
446
+ end
298
447
 
448
+ end
449
+
450
+ context "inheritance" do
451
+ class MyBase
452
+ include SimpleModel::Attributes
453
+ has_boolean :bar
454
+ has_attribute :str, :stuff
455
+ has_currency :amount, :default => BigDecimal("0.0"), :initialize => false
456
+ has_dates :some, :thing, :default => :fetch_date, :allow_blank => false, :initialize => false
457
+ alias_attribute :other, :bar
458
+ alias_attribute :other_amount, :amount
459
+
460
+ def fetch_date
461
+ Date.today
462
+ end
299
463
  end
464
+
465
+ class NewerBase < MyBase
466
+ has_boolean :foo
467
+ has_int :str
468
+ end
469
+
470
+ class NewestBase < NewerBase
471
+ alias_attribute :some_amount, :other_amount
472
+ end
473
+
300
474
  it "should merge defined attributes when class are inherited" do
301
- NewerBase.attribute_defined?(:bar).should eql(true)
302
- n = NewerBase.new
303
- n.respond_to?(:bar_will_change!).should eql(true)
475
+ expect(NewerBase).to be_attribute_defined(:bar)
476
+ newer_base = NewerBase.new
477
+ expect(newer_base).to respond_to(:bar_will_change!)
304
478
  end
305
479
 
306
480
  it "should set defaults that were not initialized should work from parent class" do
307
- n = NewerBase.new
308
- n.some.should eql(n.send(:fetch_date))
309
- n.thing.should eql(n.send(:fetch_date))
481
+ newer_base = NewerBase.new
482
+ expect(newer_base.some).to eql(newer_base.send(:fetch_date))
483
+ expect(newer_base.thing).to eql(newer_base.send(:fetch_date))
310
484
  end
311
485
 
312
486
  it "should allow redefining methods in child classes" do
313
- n = NewerBase.new
314
- n.str = '1'
315
- n.str.should eql(1)
487
+ newer_base = NewerBase.new
488
+ newer_base.str = '1'
489
+ expect(newer_base.str).to eql(1)
316
490
  end
317
491
 
318
492
  it "should set attribute from alias" do
319
- MyBase.new(:other => true).bar?.should eql(true)
320
- NewerBase.new(:other => true).bar?.should eql(true)
493
+ expect(MyBase.new(:other => true)).to be_bar
494
+ expect(NewerBase.new(:other => true)).to be_bar
321
495
  end
322
496
 
323
497
  it "should properly alias attributes from parent class" do
324
- nb = NewestBase.new(:some_amount => 1.0)
325
- nb.other_amount.should eql(1.0.to_d)
326
- nb.amount.should eql(1.0.to_d)
327
- end
328
- end
329
-
330
- after(:all) do
331
- [:OnGet,:TestDefault,:TestInit,:MyBase,:NewerBase].each do |test_klass|
332
- Object.send(:remove_const,test_klass) if defined?(test_klass)
498
+ newer_base = NewestBase.new(:some_amount => 1.0)
499
+ expect(newer_base.other_amount).to eql(1.0.to_d)
500
+ expect(newer_base.amount).to eql(1.0.to_d)
333
501
  end
334
502
  end
335
503
  end