simple_model 1.2.27 → 1.3.0

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,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