simple_model 1.2.27 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NzIwOThmYzg1NGI0ZGZjN2YwNTdhZTU3NGM2YzNmMDBlMGJkMzA2NA==
5
- data.tar.gz: !binary |-
6
- YWEwNDJjZDg4ZjExOTYxODYyMmQ0NjljZjNkY2VkOTg3Y2Q1ZjI5Nw==
2
+ SHA1:
3
+ metadata.gz: fad8b6e06b4a604873dfe174617170dce71277ab
4
+ data.tar.gz: a9e8d432e3f3f7d1abff848bc6f022f186553e99
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NDkyOTdlMDdmZTczMGI3MGQyZmZlNzliNDkzN2M2ZTY4NGU4MmNjNGZmZWI0
10
- M2M3YmMzNWQ3Njg2ZjEwZWY4YTUzYzEwMjkwNDI2NTU5ZDc4MzdhNDdhZjYx
11
- MzQ4OWRkZjY3MDczY2Q5Yzc4NTVjN2NiMjdiOWNlOGE4YzFlMGY=
12
- data.tar.gz: !binary |-
13
- YzhiNmE4MWU5ZDVhOWYzZTZlZGUyNmI1MzU1YmQxODY5MjdkMGRhNjg2MTJk
14
- MWJhZDNiNDQyY2E1YTg1NzlmM2FkODViMmNlZTRiYzhlMWEwOWVjMmRhZDZi
15
- ZDBhMzAwODQzYjM1MTBiYWIxNWI2YjNjYzBlM2Y0MGZjYzYyODc=
6
+ metadata.gz: 8e916c15d886c4c49530cf6ae29e66e93efde3532f3094cd654ff287a5b3ce8598c8947fdce2437f3b2dd5ebb16f9940c28070d595cb0f60f432bc9fc2b01e65
7
+ data.tar.gz: 2eccebd37cf6fd8909296c83cb4c0c501205364c2f029942ec7d367a72d2af5c50e2d2db0bf979314f9e34542cbf496cabb3cfc5abc9856072771efc6d3a9d83
data/.travis.yml CHANGED
@@ -1,9 +1,11 @@
1
1
  language: ruby
2
+ cache: bundler
2
3
  rvm:
3
- - "2.1"
4
- - "2.0.0"
5
- - "1.9.3"
6
- - jruby-19mode # JRuby in 1.9 mode
4
+ - 2.2
5
+ - 2.1
6
+ - 2.0.0
7
+ - 1.9.3
8
+ - jruby
7
9
  script: bundle exec rspec spec
8
10
  gemfile:
9
11
  - gemfiles/3.0.gemfile
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source "https://rubygems.org"
2
-
3
-
4
2
  # Specify your gem's dependencies in simple_model.gemspec
5
3
  gemspec
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2014 Joshua T. McKinney
1
+ Copyright (c) 2010-2015 Joshua T. McKinney
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -35,7 +35,6 @@ SimpleModel is available through [Rubygems](http://rubygems.org/gems/simple_mode
35
35
  # Attributes
36
36
  has_booleans :active, :default => true
37
37
  has_booleans :paid
38
- has_currency :price, :default => 10.0.to_currency
39
38
  has_times :created_at, :default => :now
40
39
  has_attribute :my_array, :default => []
41
40
 
@@ -79,17 +79,17 @@ end
79
79
  # ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
80
80
 
81
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
82
+ # init 0.150000 0.000000 0.150000 ( 0.149609)
83
+ # init w/attrs 1.100000 0.000000 1.100000 ( 1.101177)
84
+ # get 0.490000 0.000000 0.490000 ( 0.491134)
85
+ # get? 0.600000 0.000000 0.600000 ( 0.598875)
86
+ # set 1.170000 0.000000 1.170000 ( 1.171242)
87
+ # --------------------------------------- total: 3.510000sec
88
88
 
89
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)
90
+ # init 0.140000 0.000000 0.140000 ( 0.140109)
91
+ # init w/attrs 1.060000 0.000000 1.060000 ( 1.055176)
92
+ # get 0.490000 0.000000 0.490000 ( 0.491473)
93
+ # get? 0.600000 0.000000 0.600000 ( 0.600557)
94
+ # set 1.200000 0.010000 1.210000 ( 1.196884)
95
95
 
@@ -0,0 +1,16 @@
1
+ module SimpleModel
2
+ module Attributes
3
+ module DefaultValueHelpers
4
+
5
+ private
6
+
7
+ def new_empty_array
8
+ Array.new
9
+ end
10
+
11
+ def new_empty_hash
12
+ Hash.new
13
+ end
14
+ end
15
+ end
16
+ end
@@ -6,14 +6,12 @@ module SimpleModel
6
6
  include ActiveModel::Dirty
7
7
 
8
8
  DEFAULT_ATTRIBUTE_SETTINGS = {:attributes_method => :attributes,
9
- :allow_blank => false,
10
- :initialize => true
9
+ :allow_blank => false
11
10
  }.freeze
12
11
 
13
12
  AVAILABLE_ATTRIBUTE_METHODS = {
14
13
  :has_attribute => {:alias => :has_attributes, :options => {:allow_blank => true}},
15
14
  :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
15
  :has_date => {:cast_to => :to_date, :alias => :has_dates} ,
18
16
  :has_decimal => {:cast_to => :to_d, :alias => :has_decimals},
19
17
  :has_float => {:cast_to => :to_f, :alias => :has_floats},
@@ -21,23 +19,33 @@ module SimpleModel
21
19
  :has_time => {:cast_to => :to_time, :alias => :has_times}
22
20
  }.freeze
23
21
 
24
- attr_accessor :attributes
25
-
26
22
  def initialize(*attrs)
27
23
  attrs = attrs.extract_options!
28
- attrs = attributes_for_init(attrs)
29
24
  attrs = self.class.before_initialize.call(self,attrs) if self.class.before_initialize
30
25
  set(attrs)
26
+ defaults = default_attributes_for_init
27
+ set(defaults)
31
28
  self.class.after_initialize.call(self) if self.class.after_initialize
32
29
  end
33
30
 
34
31
  def attributes
35
- @attributes ||= HashWithIndifferentAccess.new
32
+ @attributes ||= new_attribute_store
33
+ end
34
+
35
+ def attributes=attrs
36
+ if attrs.class.name == "Hash"
37
+ if config.attributes_store == :symbol
38
+ attrs.symbolize_keys!
39
+ else
40
+ attrs.stringify_keys!
41
+ end
42
+ end
43
+ @attributes = attrs
36
44
  end
37
45
 
38
46
  # Returns true if attribute has been initialized
39
47
  def initialized?(attr)
40
- attributes.key?(attr)
48
+ attributes.has_key?(to_attr_key(attr))
41
49
  end
42
50
 
43
51
  def get(attr)
@@ -56,27 +64,27 @@ module SimpleModel
56
64
 
57
65
  def set_attribute(attr,val,opts=nil)
58
66
  opts ||= fetch_attribute_options(attr)
67
+ attr_key = to_attr_key(attr)
59
68
  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)
64
- send("#{attr}_will_change!") if (initialized?(attr) && val != attributes[attr])
65
- attributes[attr] = val
66
- opts[:after_set].call(self,val) if opts[:after_set]
69
+ ab = opts[:allow_blank]
70
+ val = fetch_default_value(opts[:default]) unless skip_set_default?(attr,opts,val,ab)
71
+ unless (opts[:boolean] ? (!ab && val.blank? && (val != false)) : (!ab && val.blank?))
72
+ val = opts[:on_set].call(self,val) if opts.has_key?(:on_set)
73
+ send("#{attr}_will_change!") if initialized?(attr) && val != attributes[attr_key]
74
+ attributes[attr_key] = val
67
75
  end
76
+ val
68
77
  end
69
78
  end
70
79
 
80
+ # TODO: Returning just val in Rails 3 HashWithIndifferentAccess causes weird issue where if value is an array the array is reset,
81
+ # revert to return to just val when Rails 3 support is dropped to improve performance
71
82
  def get_attribute(attr,opts=nil)
72
83
  opts ||= fetch_attribute_options(attr)
73
- val = attributes[attr]
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)
77
- else
78
- val
79
- end
84
+ attr_key = to_attr_key(attr)
85
+ val = attributes[attr_key]
86
+ attributes[attr_key] = fetch_default_value(opts[:default]) unless skip_get_default?(attr,opts,val)
87
+ val = attributes[attr_key]
80
88
  end
81
89
 
82
90
  def fetch_attribute_options(attr)
@@ -84,7 +92,7 @@ module SimpleModel
84
92
  end
85
93
 
86
94
  def get_attribute?(attr)
87
- return false unless val = send(attr)
95
+ return false unless val = get_attribute(attr)
88
96
  if val.respond_to?(:blank?)
89
97
  return !val.blank?
90
98
  elsif val.respond_to?(:to_b)
@@ -102,52 +110,85 @@ module SimpleModel
102
110
  get_attribute(attr)
103
111
  end
104
112
 
113
+ def raw_attribute(attr)
114
+ attributes[to_attr_key(attr)]
115
+ end
116
+
117
+ def set_raw_attribute(attr,val)
118
+ attributes[to_attr_key(attr)] = val
119
+ end
120
+
121
+ def delete_attributes(*attrs)
122
+ clear_attribute_changes(attrs) if respond_to?(:clear_attribute_changes,true) # Rails 4.2 +
123
+ attrs.each do |attr|
124
+ attributes.delete(to_attr_key(attr))
125
+ end
126
+ end
127
+ alias :delete_attribute :delete_attributes
128
+
129
+ def reset_attributes
130
+ @attributes = new_attribute_store
131
+ end
132
+
105
133
  private
106
134
 
135
+ def new_attribute_store
136
+ (config.attributes_store == :indifferent ? HashWithIndifferentAccess.new : Hash.new)
137
+ end
138
+
139
+ def to_attr_key(attr)
140
+ @_attr_cast ||= config.attibutes_store_cast
141
+ attr.send(@_attr_cast)
142
+ end
143
+
144
+ def new_attibutes_store(attrs=nil)
145
+ config.attibutes_store_class.new(attrs)
146
+ end
147
+
107
148
  def skip_get_default?(attr,opts,val)
108
- (val || !opts.key?(:default) || (opts[:boolean] && (val == false)))
149
+ (val || !opts.has_key?(:default) || (opts[:boolean] && (val == false)))
109
150
  end
110
151
 
111
- def skip_set_default?(attr,opts,val)
112
- return true if (!opts.key?(:default) ||
152
+ def skip_set_default?(attr,opts,val,ab=true)
153
+ return true if (!opts.has_key?(:default) ||
113
154
  initialized?(attr) ||
114
155
  (opts[:boolean] && (val == false)))
115
156
  blnk = val.blank?
116
- (!blnk || (blnk && opts[:allow_blank]))
157
+ (!blnk || (blnk && ab))
117
158
  end
118
159
 
119
160
  def fetch_default_value(arg)
120
- return send(arg) if (arg.is_a?(Symbol) && self.respond_to?(arg))
161
+ return send(arg) if (arg.is_a?(Symbol) && respond_to?(arg,true))
121
162
  arg
122
163
  end
123
164
 
124
165
  # Returns attribute that have defaults in a hash: {:attribute => "default value"}
125
166
  # Checks for alias attributes to ensure they are not overwritten
126
- def attributes_for_init(attrs)
127
- d = (attrs.is_a?(HashWithIndifferentAccess) ? attrs : attrs.with_indifferent_access )
128
- self.class.defined_attributes.each do |k,v|
129
- if allow_init_default?(d,k,v)
130
- d[k] = fetch_default_value(v[:default])
167
+ def default_attributes_for_init
168
+ da = {}
169
+ self.class.defined_attributes.each do |attr,opts|
170
+ if allow_init_default?(attr,opts)
171
+ da[attr] = fetch_default_value(opts[:default])
131
172
  end
132
173
  end
133
- d
174
+ da
134
175
  end
135
176
 
136
177
  # Only set default if there is a default value, initializing is allow and
137
178
  # new attributes do not have a value to set and
138
- def allow_init_default?(d,k,v)
139
- (v[:default] && v[:initialize] && (!d.key?(k) && !attributes_have_alias?(d,k)))
179
+ def allow_init_default?(attr,opts)
180
+ (opts.has_key?(:default) && (opts.has_key?(:initialize) ? opts[:initialize] : config.initialize_defaults?) && !initialized?(attr) && !initialized_alias?(attr))
140
181
  end
141
182
 
142
- def attributes_have_alias?(attrs,attr)
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?
183
+ def initialized_alias?(attr)
184
+ base_meth = self.class.alias_attributes.rassoc(attr)
185
+ base_meth && attributes.has_key?(base_meth[0])
146
186
  end
147
187
 
148
188
  def allow_attribute_action?(val,options)
149
- return true unless (options[:if] || options[:unless])
189
+ return true unless (options.has_key?(:if) || options.has_key?(:unless))
150
190
  b = true
191
+ opt = nil
151
192
  if opt = options[:if]
152
193
  if opt.is_a?(Symbol)
153
194
  if opt == :blank
@@ -173,7 +214,13 @@ module SimpleModel
173
214
  b
174
215
  end
175
216
 
217
+ def config
218
+ self.class.config
219
+ end
220
+
176
221
  module ClassMethods
222
+ attr_accessor :config
223
+
177
224
  AVAILABLE_ATTRIBUTE_METHODS.each do |method,method_options|
178
225
  define_method(method) do |*attributes|
179
226
  options = attributes.extract_options!
@@ -199,14 +246,11 @@ module SimpleModel
199
246
  # end
200
247
  #
201
248
  def new_with_store(session_hash)
202
- nw = self.new()
203
- nw.attributes = session_hash
204
- nw.set(nw.send(:attributes_for_init,session_hash))
205
- nw
249
+ self.new(:attributes => session_hash)
206
250
  end
207
251
 
208
252
  def alias_attributes
209
- @alias_attributes ||= HashWithIndifferentAccess.new
253
+ @alias_attributes ||= Hash.new
210
254
  end
211
255
 
212
256
  def alias_attributes=alias_attributes
@@ -214,7 +258,7 @@ module SimpleModel
214
258
  end
215
259
 
216
260
  def defined_attributes
217
- @defined_attributes ||= HashWithIndifferentAccess.new
261
+ @defined_attributes ||= Hash.new
218
262
  end
219
263
 
220
264
  def defined_attributes=defined_attributes
@@ -222,7 +266,15 @@ module SimpleModel
222
266
  end
223
267
 
224
268
  def attribute_defined?(attr)
225
- defined_attributes.key?(attr)
269
+ defined_attributes.has_key?(attr.to_sym)
270
+ end
271
+
272
+ # The current intent of the config is allow the managing of features at the global level and overrides options
273
+ # set at attribute definition, which may not be the most flexible and may require re-thinking for future options
274
+ # Options:
275
+ # * config.initialize_defaults default is true, if false prevents attributes with default values from auto-initializing
276
+ def config
277
+ @config ||= (superclass.respond_to?(:config) ? superclass.config.dup : SimpleModel.config.dup)
226
278
  end
227
279
 
228
280
  # The default settings for a SimpeModel class
@@ -230,7 +282,8 @@ module SimpleModel
230
282
  # * :on_set - accepts a lambda that is run when an attribute is set
231
283
  # * :on_get - accepts a lambda that is run when you get/read an attribute
232
284
  # * :default - the default value for the attribute, can be a symbol that is sent for a method
233
- # * :initialize - informations the object whether or not it should initialize the attribute with :default value, defaults to true
285
+ # * :initialize - informations the object whether or not it should initialize the attribute with :default value, defaults to true,
286
+ # and is overridden by config.initialzie_defaults
234
287
  # ** If :initialize is set to false you must set :allow_blank to false or it will never set the default value
235
288
  # * :allow_blank - when set to false, if an attributes value is blank attempts to set the default value, defaults to true
236
289
  def default_attribute_settings
@@ -258,9 +311,9 @@ module SimpleModel
258
311
  end
259
312
 
260
313
  # builds the setter and getter methods
261
- def create_attribute_methods(attributes,options)
262
- unless attributes.blank?
263
- attributes.each do |attr|
314
+ def create_attribute_methods(attrs,options)
315
+ unless attrs.blank?
316
+ attrs.each do |attr|
264
317
  define_setter_with_options(attr,options)
265
318
  define_reader_with_options(attr,options)
266
319
  add_defined_attribute(attr,options)
@@ -15,6 +15,8 @@ module SimpleModel
15
15
  require 'active_support/core_ext/module/introspection'
16
16
  require 'active_support/core_ext/object/duplicable'
17
17
  require 'active_support/core_ext/object/blank'
18
+ require 'simple_model/attributes/default_value_helpers'
19
+
18
20
 
19
21
  # == SimpleModel::Base
20
22
  #
@@ -75,6 +77,7 @@ module SimpleModel
75
77
  class Base
76
78
  include SimpleModel::Attributes
77
79
  include SimpleModel::ErrorHelpers
80
+ include SimpleModel::Attributes::DefaultValueHelpers
78
81
 
79
82
  define_model_callbacks :save, :update, :create, :destroy
80
83
 
@@ -0,0 +1,29 @@
1
+ module SimpleModel
2
+ class Config
3
+ DEFAULTS = {
4
+ :initialize_defaults => false,
5
+ :attributes_store => :string # OPTIONS => :string, :symbol, :indifferent
6
+ }.freeze
7
+
8
+ ATTRIBUTE_STORES = {
9
+ :symbol => :to_sym,
10
+ :string => :to_s,
11
+ :indifferent => :to_s
12
+ }.freeze
13
+
14
+ attr_accessor :initialize_defaults
15
+ alias :initialize_defaults? :initialize_defaults
16
+
17
+ attr_accessor :attributes_store
18
+
19
+ def initialize
20
+ DEFAULTS.each do |setting, val|
21
+ self.send("#{setting}=", val)
22
+ end
23
+ end
24
+
25
+ def attibutes_store_cast
26
+ ATTRIBUTE_STORES[attributes_store]
27
+ end
28
+ end
29
+ end
@@ -40,11 +40,6 @@ module SimpleModel
40
40
  (((((self)*mulitplier).round).to_f)/mulitplier)
41
41
  end
42
42
 
43
- # Returns a BigDecimal object rounded to the nearest hundredth
44
- # Why decimal?..because precision matters when dealing with money ;)
45
- def to_currency
46
- self.to_d.round(2)
47
- end
48
43
 
49
44
  def to_time
50
45
  Time.at(self)
@@ -120,8 +115,6 @@ module SimpleModel
120
115
  def to_d
121
116
  gsub(/[^0-9\.\+\-]/, '').core_to_d
122
117
  end
123
- alias :to_currency :to_d
124
-
125
118
  end
126
119
 
127
120
  BigDecimal.class_eval do
@@ -1,3 +1,3 @@
1
1
  module SimpleModel
2
- VERSION = "1.2.27"
2
+ VERSION = "1.3.0"
3
3
  end
data/lib/simple_model.rb CHANGED
@@ -1,49 +1,34 @@
1
- #--
2
- # Copyright (c) 2010-2014 Joshua Thomas Mckinney
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
1
+ require 'active_support'
2
+ require 'active_support/i18n'
3
+ require 'active_support/time'
4
+ require 'active_support/core_ext/class/attribute'
5
+ require 'active_support/core_ext/class/attribute_accessors'
6
+ require 'active_support/core_ext/class/delegating_attributes'
7
+ require 'active_support/core_ext/class/attribute'
8
+ require 'active_support/core_ext/array/extract_options'
9
+ require 'active_support/core_ext/hash/deep_merge'
10
+ require 'active_support/core_ext/hash/indifferent_access'
11
+ require 'active_support/core_ext/hash/slice'
12
+ require 'active_support/core_ext/string/behavior'
13
+ require 'active_support/core_ext/kernel/singleton_class'
14
+ require 'active_support/core_ext/module/delegation'
15
+ require 'active_support/core_ext/module/introspection'
16
+ require 'active_support/core_ext/object/duplicable'
17
+ require 'active_support/core_ext/object/blank'
18
+ require 'active_model'
19
+ require "simple_model/extend_core"
20
+ require 'simple_model/exceptions'
21
+ require 'simple_model/config'
22
+ require "simple_model/attributes/default_value_helpers"
23
+ require "simple_model/attributes"
24
+ require "simple_model/error_helpers"
25
+ require "simple_model/base"
26
+ require 'simple_model/simple_model_railtie.rb' if defined?(Rails)
27
+
23
28
  module SimpleModel
24
- require 'active_support'
25
- require 'active_support/i18n'
26
- require 'active_support/time'
27
- require 'active_support/core_ext/class/attribute'
28
- require 'active_support/core_ext/class/attribute_accessors'
29
- require 'active_support/core_ext/class/delegating_attributes'
30
- require 'active_support/core_ext/class/attribute'
31
- require 'active_support/core_ext/array/extract_options'
32
- require 'active_support/core_ext/hash/deep_merge'
33
- require 'active_support/core_ext/hash/indifferent_access'
34
- require 'active_support/core_ext/hash/slice'
35
- require 'active_support/core_ext/string/behavior'
36
- require 'active_support/core_ext/kernel/singleton_class'
37
- require 'active_support/core_ext/module/delegation'
38
- require 'active_support/core_ext/module/introspection'
39
- require 'active_support/core_ext/object/duplicable'
40
- require 'active_support/core_ext/object/blank'
41
- require 'active_model'
42
- require "simple_model/extend_core"
43
- require 'simple_model/exceptions'
44
- require "simple_model/attributes"
45
- require "simple_model/error_helpers"
46
- require "simple_model/validation"
47
- require "simple_model/base"
48
- require 'simple_model/simple_model_railtie.rb' if defined?(Rails)
29
+ class << self
30
+ def config
31
+ @config ||= SimpleModel::Config.new
32
+ end
33
+ end
49
34
  end
@@ -1,9 +1,4 @@
1
1
  require 'spec_helper.rb'
2
-
3
- class AttributesTest
4
- include SimpleModel::Attributes
5
- end
6
-
7
2
  describe SimpleModel::Attributes do
8
3
 
9
4
  # We need a clean class for each spec
@@ -19,6 +14,10 @@ describe SimpleModel::Attributes do
19
14
 
20
15
  context "class methods" do
21
16
 
17
+ describe '#config' do
18
+ it { expect(AttributesTest.config).to be_a(SimpleModel::Config) }
19
+ end
20
+
22
21
  describe '#create_attribute_methods' do
23
22
  context "no options" do
24
23
  before(:each) do
@@ -58,7 +57,16 @@ describe SimpleModel::Attributes do
58
57
  let(:attributes_test) { AttributesTest.new() }
59
58
 
60
59
  it "should work" do
61
- expect(attributes_test.attributes[:with_default]).to eql('foo')
60
+ expect(attributes_test.raw_attribute(:with_default)).to eql('foo')
61
+ end
62
+
63
+ context 'should override config setting' do
64
+ it "should still work" do
65
+ AttributesTest.config.initialize_defaults = false
66
+ expect(attributes_test.initialized?(:with_default)).to eql(true)
67
+ end
68
+
69
+ it {expect(attributes_test.with_default).to eql('foo')}
62
70
  end
63
71
 
64
72
  end
@@ -70,13 +78,20 @@ describe SimpleModel::Attributes do
70
78
 
71
79
  let(:attributes_test) { AttributesTest.new() }
72
80
 
73
- it "should work" do
74
- expect(attributes_test.attributes).to_not have_key(:with_default_no_init)
75
- end
81
+ it { expect(attributes_test.attributes).to_not have_key(:with_default_no_init) }
76
82
 
77
83
  it "should set on get" do
78
84
  expect(attributes_test.with_default_no_init).to eql('foo')
79
85
  end
86
+
87
+ context 'config.initialize_defaults? == false' do
88
+
89
+ it "should override config setting" do
90
+ AttributesTest.config.initialize_defaults = true
91
+ expect(attributes_test.attributes.key?(:with_default)).to eql(false)
92
+ end
93
+
94
+ end
80
95
  end
81
96
 
82
97
  context "set to a symbol for a method" do
@@ -379,7 +394,45 @@ describe SimpleModel::Attributes do
379
394
 
380
395
  end # end class methods
381
396
 
397
+ describe '#attributes' do
398
+ it { expect(AttributesTest.new).to respond_to(:attributes) }
399
+ it { expect(AttributesTest.new.attributes).to be_a(Hash)}
400
+ context "set hash with string keys" do
401
+ let(:attrs) do
402
+ {'test1' => '2', 'test2' => '2'}
403
+ end
404
+ let(:set_attrs) {AttributesTest.new(:attributes => attrs)}
405
+ it {expect(set_attrs.raw_attribute(:test1)).to eql('2')}
406
+ it {expect(set_attrs.raw_attribute('test1')).to eql('2')}
407
+ end
408
+ context "set hash with string keys" do
409
+ let(:attrs) do
410
+ {:test1 => '2', :test2 => '2'}
411
+ end
412
+ let(:set_attrs) {AttributesTest.new(:attributes => attrs)}
413
+ it {expect(set_attrs.raw_attribute(:test1)).to eql('2')}
414
+ it {expect(set_attrs.raw_attribute('test1')).to eql('2')}
415
+ end
416
+ context "set with HashWithIndifferentAccess" do
417
+ let(:attrs) do
418
+ {:test1 => '2', :test2 => '2'}.with_indifferent_access
419
+ end
420
+ let(:set_attrs) {AttributesTest.new(:attributes => attrs)}
421
+ it {expect(set_attrs.raw_attribute(:test1)).to eql('2')}
422
+ it {expect(set_attrs.raw_attribute('test1')).to eql('2')}
423
+ end
424
+ end
382
425
 
426
+ describe '#delete_attributes' do
427
+ it "should work" do
428
+ AttributesTest.has_attributes(:foo, :bar,:fred)
429
+ test_attr = AttributesTest.new(:foo => "foo", :bar => "bar", :fred => 'stone')
430
+ test_attr.delete_attributes(:foo, :bar)
431
+ expect(test_attr).to_not be_initialized(:foo)
432
+ expect(test_attr).to_not be_initialized(:bar)
433
+ expect(test_attr).to be_initialized(:fred)
434
+ end
435
+ end
383
436
 
384
437
  context "initializing" do
385
438
 
@@ -389,17 +442,9 @@ describe SimpleModel::Attributes do
389
442
 
390
443
  let(:init_test) { AttributesTest.new(:test1 => '1', :test2 => '2') }
391
444
 
392
-
393
445
  it { expect(init_test.test1).to eql('1') }
394
446
  it { expect(init_test.test2).to eql('2') }
395
447
 
396
- describe '#attributes' do
397
- it { expect(init_test).to respond_to(:attributes) }
398
- it { expect(init_test.attributes).to be_a(HashWithIndifferentAccess)}
399
- end
400
-
401
-
402
-
403
448
  describe '#before_initialize' do
404
449
 
405
450
  context "before_initialize is not a Proc" do
@@ -445,6 +490,31 @@ describe SimpleModel::Attributes do
445
490
  end
446
491
  end
447
492
 
493
+ context "defaults" do
494
+ before(:each) do
495
+ AttributesTest.config.initialize_defaults = true
496
+ AttributesTest.has_attribute :has_def, :default => "Test"
497
+ AttributesTest.has_attribute :has_other, :default => "Other"
498
+ AttributesTest.has_attribute :has_derived, :default => :default_derived
499
+
500
+ class AttributesTest
501
+ def default_derived
502
+ val = "Derived" if has_def == "Test"
503
+ end
504
+ end
505
+ end
506
+
507
+ let(:defaults_test) { AttributesTest.new(:has_other => 'Foo') }
508
+
509
+ it { expect(defaults_test.initialized?(:has_def)).to eql(true)}
510
+ it { expect(defaults_test.has_def).to eql("Test")}
511
+
512
+ it { expect(defaults_test.initialized?(:has_other)).to eql(true)}
513
+ it { expect(defaults_test.has_other).to eql("Foo")}
514
+
515
+ it { expect(defaults_test.initialized?(:has_derived)).to eql(true)}
516
+ it { expect(defaults_test.has_derived).to eql("Derived")}
517
+ end
448
518
  end
449
519
 
450
520
  context "inheritance" do
@@ -452,7 +522,7 @@ describe SimpleModel::Attributes do
452
522
  include SimpleModel::Attributes
453
523
  has_boolean :bar
454
524
  has_attribute :str, :stuff
455
- has_currency :amount, :default => BigDecimal("0.0"), :initialize => false
525
+ has_decimal :amount, :default => BigDecimal("0.0"), :initialize => false
456
526
  has_dates :some, :thing, :default => :fetch_date, :allow_blank => false, :initialize => false
457
527
  alias_attribute :other, :bar
458
528
  alias_attribute :other_amount, :amount
@@ -500,4 +570,30 @@ describe SimpleModel::Attributes do
500
570
  expect(newer_base.amount).to eql(1.0.to_d)
501
571
  end
502
572
  end
573
+ context 'REGRESSION' do
574
+ context 'default is an array that is not initialized (ONlY FAILS IN RAILS ~> 3.0)' do
575
+ before(:each) do
576
+ class InitArray < SimpleModel::Base
577
+ self.config.attributes_store = :indifferent
578
+ has_attribute :conditions, :default => :new_array
579
+
580
+ def new_array
581
+ [[]]
582
+ end
583
+
584
+ def add_one
585
+ conditions << 1
586
+ end
587
+ end
588
+ end
589
+
590
+ it "should not rest amount to default" do
591
+ test_array = InitArray.new
592
+ expect(test_array.attributes).to be_a(HashWithIndifferentAccess)
593
+ expect(test_array).to_not be_initialized(:conditions)
594
+ test_array.add_one
595
+ expect(test_array.conditions).to eql([[],1])
596
+ end
597
+ end
598
+ end
503
599
  end
@@ -25,7 +25,7 @@ describe SimpleModel::Base do
25
25
  base_test = BaseTest.new()
26
26
 
27
27
  base_test.save
28
- base_test.foo.should eql("test")
28
+ expect(base_test.foo).to eql("test")
29
29
  end
30
30
 
31
31
  it "should be false if validation fails" do
@@ -36,7 +36,6 @@ describe SimpleModel::Base do
36
36
  return true
37
37
  end
38
38
 
39
-
40
39
  base_test = BaseTest.new()
41
40
  expect(base_test).to_not be_valid
42
41
  expect(base_test.save).to eql(false)
@@ -137,6 +136,7 @@ describe SimpleModel::Base do
137
136
  before(:each) do
138
137
  class TestStuff < SimpleModel::Base
139
138
  has_attribute :bar
139
+ has_attribute :my_array, :default => :new_empty_array
140
140
  validates_presence_of :bar
141
141
  end
142
142
 
@@ -89,10 +89,4 @@ describe SimpleModel::ExtendCore, 'String.rb' do
89
89
  it { expect("$5,000.006".to_f).to eql(5000.006) }
90
90
  end
91
91
  end
92
-
93
- describe '#to_currency' do
94
- context "contains non-numeric values" do
95
- it { expect("$5,000.006".to_currency).to eql(BigDecimal("5000.006")) }
96
- end
97
- end
98
92
  end
data/spec/spec_helper.rb CHANGED
@@ -1,18 +1,93 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- #$LOAD_PATH.unshift(File.dirname(__FILE__))
3
- require 'simple_model'
1
+ require 'rubygems'
4
2
  require 'rspec'
5
- require 'bundler/setup'
3
+ require 'rspec/autotest'
4
+ require 'simple_model'
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
8
+ # file to always be loaded, without a need to explicitly require it in any files.
9
+ #
10
+ # Given that it is always loaded, you are encouraged to keep this file as
11
+ # light-weight as possible. Requiring heavyweight dependencies from this file
12
+ # will add to the boot time of your test suite on EVERY test run, even for an
13
+ # individual file that may not need all of that loaded. Instead, consider making
14
+ # a separate helper file that requires the additional dependencies and performs
15
+ # the additional setup, and require it from the spec files that actually need it.
16
+ #
17
+ # The `.rspec` file also contains a few flags that are not defaults but that
18
+ # users commonly want.
19
+ #
20
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
21
+ RSpec.configure do |config|
22
+ # rspec-expectations config goes here. You can use an alternate
23
+ # assertion/expectation library such as wrong or the stdlib/minitest
24
+ # assertions if you prefer.
25
+ config.expect_with :rspec do |expectations|
26
+ # This option will default to `true` in RSpec 4. It makes the `description`
27
+ # and `failure_message` of custom matchers include text for helper methods
28
+ # defined using `chain`, e.g.:
29
+ # be_bigger_than(2).and_smaller_than(4).description
30
+ # # => "be bigger than 2 and smaller than 4"
31
+ # ...rather than:
32
+ # # => "be bigger than 2"
33
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
34
+ end
6
35
 
36
+ # rspec-mocks config goes here. You can use an alternate test double
37
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
38
+ config.mock_with :rspec do |mocks|
39
+ # Prevents you from mocking or stubbing a method that does not exist on
40
+ # a real object. This is generally recommended, and will default to
41
+ # `true` in RSpec 4.
42
+ mocks.verify_partial_doubles = true
43
+ end
7
44
 
45
+ # The settings below are suggested to provide a good initial experience
46
+ # with RSpec, but feel free to customize to your heart's content.
47
+ =begin
48
+ # These two settings work together to allow you to limit a spec run
49
+ # to individual examples or groups you care about by tagging them with
50
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
51
+ # get run.
52
+ config.filter_run :focus
53
+ config.run_all_when_everything_filtered = true
8
54
 
9
- # Requires supporting files with custom matchers and macros, etc,
10
- # in ./support/ and its subdirectories.
11
- #Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
55
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
56
+ # For more details, see:
57
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
58
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
59
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
60
+ config.disable_monkey_patching!
12
61
 
62
+ # This setting enables warnings. It's recommended, but in some cases may
63
+ # be too noisy due to issues in dependencies.
64
+ config.warnings = true
13
65
 
14
- RSpec.configure do |config|
66
+ # Many RSpec users commonly either run the entire suite or an individual
67
+ # file, and it's useful to allow more verbose output when running an
68
+ # individual spec file.
69
+ if config.files_to_run.one?
70
+ # Use the documentation formatter for detailed output,
71
+ # unless a formatter has already been configured
72
+ # (e.g. via a command-line flag).
73
+ config.default_formatter = 'doc'
74
+ end
15
75
 
76
+ # Print the 10 slowest examples and example groups at the
77
+ # end of the spec run, to help surface which specs are running
78
+ # particularly slow.
79
+ config.profile_examples = 10
16
80
 
17
- end
81
+ # Run specs in random order to surface order dependencies. If you find an
82
+ # order dependency and want to debug it, you can fix the order by providing
83
+ # the seed, which is printed after each run.
84
+ # --seed 1234
85
+ config.order = :random
18
86
 
87
+ # Seed global randomization in this process using the `--seed` CLI option.
88
+ # Setting this allows you to use `--seed` to deterministically reproduce
89
+ # test failures related to randomization by passing the same `--seed` value
90
+ # as the one that triggered the failure.
91
+ Kernel.srand config.seed
92
+ =end
93
+ end
metadata CHANGED
@@ -1,95 +1,95 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.27
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua T Mckinney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-24 00:00:00.000000000 Z
11
+ date: 2015-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3.0'
20
- - - <
20
+ - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '5.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ! '>='
27
+ - - ">="
28
28
  - !ruby/object:Gem::Version
29
29
  version: '3.0'
30
- - - <
30
+ - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '5.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activemodel
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ! '>='
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '3.0'
40
- - - <
40
+ - - "<"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '5.0'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ! '>='
47
+ - - ">="
48
48
  - !ruby/object:Gem::Version
49
49
  version: '3.0'
50
- - - <
50
+ - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '5.0'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: rspec
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - ! '>='
57
+ - - ">="
58
58
  - !ruby/object:Gem::Version
59
59
  version: '0'
60
60
  type: :development
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - ! '>='
64
+ - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: rspec-autotest
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - ! '>='
71
+ - - ">="
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
- - - ! '>='
78
+ - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: autotest
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - ! '>='
85
+ - - ">="
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
- - - ! '>='
92
+ - - ">="
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  description: Simpifies building tableless models or models backed by webservices.
@@ -100,9 +100,9 @@ executables: []
100
100
  extensions: []
101
101
  extra_rdoc_files: []
102
102
  files:
103
- - .gitignore
104
- - .rspec
105
- - .travis.yml
103
+ - ".gitignore"
104
+ - ".rspec"
105
+ - ".travis.yml"
106
106
  - Gemfile
107
107
  - LICENSE.txt
108
108
  - README.md
@@ -116,18 +116,19 @@ files:
116
116
  - gemfiles/4.2.gemfile
117
117
  - lib/simple_model.rb
118
118
  - lib/simple_model/attributes.rb
119
+ - lib/simple_model/attributes/default_value_helpers.rb
119
120
  - lib/simple_model/base.rb
121
+ - lib/simple_model/config.rb
120
122
  - lib/simple_model/error_helpers.rb
121
123
  - lib/simple_model/exceptions.rb
122
124
  - lib/simple_model/extend_core.rb
123
125
  - lib/simple_model/simple_model_railtie.rb
124
- - lib/simple_model/validation.rb
125
126
  - lib/simple_model/version.rb
126
127
  - simple_model.gemspec
127
- - spec/attributes_spec.rb
128
- - spec/base_spec.rb
129
- - spec/error_helpers_spec.rb
130
- - spec/extend_core_spec.rb
128
+ - spec/simple_model/attributes_spec.rb
129
+ - spec/simple_model/base_spec.rb
130
+ - spec/simple_model/error_helpers_spec.rb
131
+ - spec/simple_model/extend_core_spec.rb
131
132
  - spec/spec_helper.rb
132
133
  homepage: ''
133
134
  licenses: []
@@ -138,23 +139,23 @@ require_paths:
138
139
  - lib
139
140
  required_ruby_version: !ruby/object:Gem::Requirement
140
141
  requirements:
141
- - - ! '>='
142
+ - - ">="
142
143
  - !ruby/object:Gem::Version
143
144
  version: '0'
144
145
  required_rubygems_version: !ruby/object:Gem::Requirement
145
146
  requirements:
146
- - - ! '>='
147
+ - - ">="
147
148
  - !ruby/object:Gem::Version
148
149
  version: '0'
149
150
  requirements: []
150
151
  rubyforge_project: simple_model
151
- rubygems_version: 2.4.2
152
+ rubygems_version: 2.4.3
152
153
  signing_key:
153
154
  specification_version: 4
154
155
  summary: Simpifies building tableless models or models backed by webservices
155
156
  test_files:
156
- - spec/attributes_spec.rb
157
- - spec/base_spec.rb
158
- - spec/error_helpers_spec.rb
159
- - spec/extend_core_spec.rb
157
+ - spec/simple_model/attributes_spec.rb
158
+ - spec/simple_model/base_spec.rb
159
+ - spec/simple_model/error_helpers_spec.rb
160
+ - spec/simple_model/extend_core_spec.rb
160
161
  - spec/spec_helper.rb
@@ -1,66 +0,0 @@
1
- module SimpleModel
2
- module Validation
3
- def validates_presence_of(*attr_names)
4
- options = attr_names.extract_options!
5
- #set defaults
6
- options[:message] = "cannot be blank." if options[:message].blank?
7
- attr_names.each do |attr|
8
- break if conditional?(options)
9
-
10
- errors.add(attr, options[:message]) if send(attr).blank?
11
- end
12
- end
13
-
14
- def validates_format_of(*attr_names)
15
- options = attr_names.extract_options!
16
- #set defaults
17
- options[:message] = "is an invalid format." if options[:message].blank?
18
-
19
- attr_names.each do |attr|
20
- break if conditional?(options)
21
-
22
- method = send(attr)
23
- unless method.blank?
24
- errors.add(attr, options[:message]) unless method.to_s.match(options[:with])
25
- end
26
- end
27
- end
28
-
29
- def validates_length_of(*attr_names)
30
- options = attr_names.extract_options!
31
-
32
- attr_names.each do |attr|
33
- break if conditional?(options)
34
-
35
- att_method = send(attr)
36
- unless att_method.blank?
37
- errors.add(attr,(options[:message].blank? ? "must equal #{options[:is]} characters in length." : options[:message])) if options[:is] && att_method.to_s.length != options[:is]
38
- errors.add(attr,(options[:message].blank? ? "cannot have more than #{options[:maximum]} characters in length." : options[:message])) if options[:maximum] && att_method.to_s.length > options[:maximum]
39
- errors.add(attr,(options[:message].blank? ? "cannot have less than #{options[:minimum]} characters in length." : options[:message])) if options[:minimum] && att_method.to_s.length < options[:minimum]
40
- end
41
- end
42
- end
43
-
44
- def validates_inclusion_of(*attr_names)
45
- options = attr_names.extract_options!
46
-
47
- first = options[:in].first
48
- last = options[:in].last
49
- options[:message] = "must be greater than or equal to #{first} and less than or equal to #{last}" if options[:message].blank?
50
- attr_names.each do |attr|
51
- break if conditional?(options)
52
- attr_method = send(attr).to_f
53
- unless attr_method.blank?
54
- errors.add(attr,options[:message]) if attr_method < first || attr_method > last
55
- end
56
- end
57
- end
58
-
59
- private
60
- def conditional?(options)
61
- return true unless ((options[:if].blank? && options[:unless].blank?) ||
62
- !options[:if].blank? && send(options[:if])) ||
63
- (!options[:unless].blank? && !send(options[:unless]))
64
- end
65
- end
66
- end