simple_model 1.2.26 → 1.2.27

Sign up to get free protection for your applications and to get access to all the features.
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