simple_model 1.1.1 → 1.2.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.
@@ -4,26 +4,13 @@ module SimpleModel
4
4
  require 'date'
5
5
  require 'bigdecimal'
6
6
  require 'bigdecimal/util'
7
-
8
- Object.class_eval do
9
-
10
- # Expects an array of symboles representing methods for casting the object
11
- # EX: "1".cast_to(:float) # => 1.0
12
- def cast_to(methods=[])
13
- val = self
14
- methods.each do |method|
15
- val = val.send(method)
16
- end
17
- val
18
- end
19
- end
20
7
 
21
- Float.class_eval do
22
-
23
- # any value greater than 0.0 is true
8
+ Float.class_eval do
9
+ # that does not equal 0.0 is true
24
10
  def to_b
25
- self > 0.0
11
+ self != 0.0
26
12
  end
13
+
27
14
  # Rounds float to the precision specified
28
15
  # 100.5235.round_to #=> 101.0
29
16
  # 100.5235.round_to(1) #=> 101.5
@@ -40,8 +27,7 @@ module SimpleModel
40
27
  end
41
28
 
42
29
  # Returns a string with representation of currency, rounded to nearest hundredth
43
- def to_currency_s(symbol="$")
44
-
30
+ def to_currency_s(symbol="$")
45
31
  num = self.round_to(2).to_s
46
32
  neg = num.include?("-")
47
33
  while num.index('.') != (num.length-3)
@@ -59,9 +45,16 @@ module SimpleModel
59
45
  end
60
46
  num
61
47
  end
48
+
49
+ def to_time
50
+ Time.at(self)
51
+ end
52
+
53
+ def to_date
54
+ Time.at(self).to_date
55
+ end
62
56
  end
63
57
 
64
-
65
58
  #Extend Ruby String.rb
66
59
  String.class_eval do
67
60
 
@@ -70,21 +63,22 @@ module SimpleModel
70
63
  ['1',"true", "t"].include?(self)
71
64
  end
72
65
 
73
-
74
66
  # Takes known US formatted date/time strings (MM/DD/YYYY TIME) and converts
75
- # them to international format (YYYY/MM/DD TIME)
67
+ # them to international format (YYYY/MM/DD TIME). Also cleans up C# JSON
68
+ # Date (really a time integer) value.
76
69
  #
77
- # * safe_date_string("12/31/2010") # => '2010-12-31'
78
- # * safe_date_string("12/31/2010T23:30:25") # => '2010-12-31T23:30:25'
79
- # * safe_date_string("12/31/2010 23:30:25") # => '2010-12-31 23:30:25'
70
+ # * safe_date_string("12/31/2010") # => '2010-12-31'
71
+ # * safe_date_string("12/31/2010T23:30:25") # => '2010-12-31T23:30:25'
72
+ # * safe_date_string("12/31/2010 23:30:25") # => '2010-12-31 23:30:25'
73
+ # * safe_date_string("\/Date(1310669017000)\/") # =>
80
74
  def safe_datetime_string
81
- date = self
82
- date_string = ""
83
- if date[0..9].match(/^(0[1-9]|[1-9]|1[012])[- \/.]([1-9]|0[1-9]|[12][0-9]|3[01])[- \/.][0-9][0-9][0-9][0-9]/)
84
- if date.include?("/")
85
- split = date.split("/")
75
+ safe_date = nil
76
+ if self[0..9].match(/^(0[1-9]|[1-9]|1[012])[- \/.]([1-9]|0[1-9]|[12][0-9]|3[01])[- \/.][0-9][0-9][0-9][0-9]/)
77
+ safe_date = ""
78
+ if self.include?("/")
79
+ split = self.split("/")
86
80
  else
87
- split = date.split("-")
81
+ split = self.split("-")
88
82
  end
89
83
  time = ""
90
84
  if split[2].length > 4
@@ -92,108 +86,111 @@ module SimpleModel
92
86
  split[2] = split[2][0..3]
93
87
  end
94
88
  if split.length == 3 && split[2].length == 4
95
- date_string << "#{split[2]}-#{split[0]}-#{split[1]}"
96
- date_string << "#{time}" unless time.nil? || time.to_s.length == 0
89
+ safe_date << "#{split[2]}-#{split[0]}-#{split[1]}"
90
+ safe_date << "#{time}" unless time.nil? || time.to_s.length == 0
97
91
  end
92
+ elsif self.match(/^\/Date\(/)
93
+ safe_date = Time.at(((self.gsub(/(\/Date\()/,"")).gsub(/\)\/$/,"").to_f) / 1000).to_s
94
+ else
95
+ safe_date = self
98
96
  end
99
- date_string = date if date_string.length == 0
100
- date_string
97
+ safe_date
101
98
  end
102
99
 
103
100
  # Use safe_datetime_string help with those pesky US date formats in Ruby 1.9
101
+ # or to change an integer string to date
104
102
  def to_date
103
+ return safe_datetime_string.to_i.to_date if self.match(/^+d$/)
105
104
  Date.parse(safe_datetime_string)
106
105
  end
107
106
 
108
107
  # Use safe_datetime_string help with those pesky US date formats in Ruby 1.9
108
+ # or to change an integer string to date
109
109
  def to_time
110
+ return safe_datetime_string.to_i.to_time if self.match(/^+d$/)
110
111
  Time.parse(safe_datetime_string)
111
112
  end
112
113
 
113
-
114
- alias :old_to_f :to_f
114
+ alias :core_to_f :to_f
115
115
 
116
116
  # Remove none numeric characters then run default ruby float cast
117
117
  def to_f
118
- gsub(/[^0-9\.\+\-]/, '').old_to_f
118
+ gsub(/[^0-9\.\+\-]/, '').core_to_f
119
119
  end
120
-
121
- # Cleans all none pertinent characters and returns a BigDecimal rounded to nearest hundredth
122
- # Why decimal?..because precision matters when dealing with money ;)
123
- def to_currency
124
- gsub(/[^0-9\.\+\-]/, '').to_d.round(2)
120
+
121
+ alias :core_to_d :to_d
122
+
123
+ def to_d
124
+ gsub(/[^0-9\.\+\-]/, '').core_to_d
125
125
  end
126
-
126
+ alias :to_currency :to_d
127
+
128
+ end
127
129
 
128
- # Parse a full name into it's parts. http://pastie.org/867415
129
- # Based on :http://artofmission.com/articles/2009/5/31/parse-full-names-with-ruby
130
- #
131
- # Options:
132
- # +name+
133
- # +seperate_middle_name+ defaults to true. if false, will combine middle name into last name.
134
-
135
- def parse_name(seperate_middle_name=true)
136
- str = self
137
- if str.include?(',') # Rearrange names formatted as Doe, John C. to John C. Doe
138
- temp = str.split(',')
139
- temp << temp[0]
140
- temp.delete_at(0)
141
- str = temp.join(" ")
142
-
143
- end
144
- parts = str.split # First, split the name into an array
145
-
146
- parts.each_with_index do |part, i|
147
- # If any part is "and", then put together the two parts around it
148
- # For example, "Mr. and Mrs." or "Mickey and Minnie"
149
- if part=~/^(and|&)$/i && i > 0
150
- parts[i-1] = [parts.delete_at(i+1), parts.at(i).downcase, parts.delete_at(i-1)].reverse * " "
151
- end
152
- end if self=~/\s(and|&)\s/i # optimize
153
-
154
- { :prefix => (parts.shift if parts[0]=~/^\w+\./),
155
- :first_name => parts.shift || "", # if name is "", then atleast first_name should be ""
156
- :suffix => (parts.pop if parts[-1]=~/(\w+\.|[IVXLM]+|[A-Z]+\.|(?i)jr|(?i)sr )$/),
157
- :last_name => (seperate_middle_name ? parts.pop : parts.slice!(0..-1) * " "),
158
- :middle_name => (parts * " " unless parts.empty?) }
130
+ BigDecimal.class_eval do
131
+ def to_currency_s(symbol="$")
132
+ self.to_f.to_currency_s(symbol)
133
+ end
134
+
135
+ def to_b
136
+ self != 0.0
159
137
  end
160
138
  end
161
139
 
162
- BigDecimal.class_eval do
163
- def to_currency_s(symbol="$")
164
- self.to_f.to_currency_s(symbol)
165
- end
166
- end
167
-
168
140
  Fixnum.class_eval do
169
- #Any value greater than 0 is true
170
- def to_b
171
- self > 0
141
+ def to_currency_s(symbol="$")
142
+ self.to_f.to_currency_s(symbol)
172
143
  end
173
144
 
174
- def to_d
175
- BigDecimal.new("#{self}.0")
145
+ unless Fixnum.instance_methods.include?(:to_b)
146
+ #Any value greater than 0 is true
147
+ def to_b
148
+ self > 0
149
+ end
150
+ end
151
+
152
+ unless Fixnum.instance_methods.include?(:to_d)
153
+ def to_d
154
+ BigDecimal.new("#{self}.0")
155
+ end
156
+ end
157
+
158
+ unless Fixnum.instance_methods.include?(:to_date)
159
+ def to_date
160
+ Time.at(self).to_date
161
+ end
162
+ end
163
+ unless Fixnum.instance_methods.include?(:to_time)
164
+ def to_time
165
+ Time.at(self)
166
+ end
176
167
  end
177
168
  end
178
169
 
179
170
  NilClass.class_eval do
180
- def to_b
181
- false
171
+ unless NilClass.instance_methods.include?(:to_b)
172
+ def to_b
173
+ false
174
+ end
182
175
  end
183
-
184
- def to_d
185
- BigDecimal.new("0.0")
176
+ unless NilClass.instance_methods.include?(:to_d)
177
+ def to_d
178
+ BigDecimal.new("0.0")
179
+ end
186
180
  end
187
181
  end
188
182
  TrueClass.class_eval do
189
-
190
- def to_b
191
- self
183
+ unless TrueClass.instance_methods.include?(:to_b)
184
+ def to_b
185
+ self
186
+ end
192
187
  end
193
188
  end
194
189
  FalseClass.class_eval do
195
- def to_b
196
- self
190
+ unless FalseClass.instance_methods.include?(:to_b)
191
+ def to_b
192
+ self
193
+ end
197
194
  end
198
195
  end
199
196
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleModel
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/simple_model.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2010-2011 Joshua Thomas Mckinney
2
+ # Copyright (c) 2010-2012 Joshua Thomas Mckinney
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -21,20 +21,30 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
  module SimpleModel
24
-
25
- #Get those rails goodies
26
24
  require 'active_support'
27
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'
28
41
  require 'active_model'
29
-
30
- # Load as necessary
31
- autoload :ExtendCore, "simple_model/extend_core"
32
- autoload :Attributes, "simple_model/attributes"
33
- autoload :ErrorHelpers, "simple_model/error_helpers"
34
- autoload :Validation, "simple_model/validation"
35
- autoload :Base, "simple_model/base"
36
-
37
- #Railtie
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"
38
48
  require 'simple_model/simple_model_railtie.rb' if defined?(Rails)
39
-
49
+
40
50
  end
data/simple_model.gemspec CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_development_dependency 'rspec'
19
19
  s.add_development_dependency 'autotest'
20
+ s.add_development_dependency 'debugger'
20
21
 
21
22
  s.rubyforge_project = "simple_model"
22
23
 
@@ -9,84 +9,159 @@ describe SimpleModel::Attributes do
9
9
  @init = TestInit.new(:test1 => "1", :test2 => '2')
10
10
  end
11
11
 
12
-
13
12
  it "should set provided attributes on initialize" do
14
-
15
13
  @init.test1.should eql("1")
16
14
  @init.test2.should eql("2")
17
15
  end
18
16
 
19
17
  it "should include set attributes in attributes hash" do
20
- @init.attributes.class.should eql(Hash)
18
+ @init.attributes.should be_kind_of(ActiveSupport::HashWithIndifferentAccess)
21
19
  @init.attributes[:test1].should eql("1")
22
20
  @init.attributes[:test2].should eql("2")
23
21
  end
24
-
25
- end
26
- describe SimpleModel::Attributes, 'define_reader_with_options' do
27
- before(:each) do
28
- class TestDefault
29
- include SimpleModel::Attributes
30
- attr_accessor :test
31
- define_reader_with_options :test, :default => "test"
22
+
23
+ context '#new_with_store'do
24
+ it "should use the provided object as the attribute store" do
25
+ my_store = {:test1 => 1,:test2 => 2}
26
+ new = TestInit.new_with_store(my_store)
27
+ new.test1 = 3
28
+ new.test1.should eql(3)
29
+ my_store[:test1].should eql(new.test1)
32
30
  end
33
31
  end
34
-
35
- it "should define setter method with default value" do
36
- default = TestDefault.new
37
- default.test.should eql("test")
38
- end
39
- it "should not intefer with setting" do
40
- default = TestDefault.new
41
- default.test = "New"
42
- default.test.should eql("New")
43
- end
44
32
 
45
- context 'default value is a symbol' do
46
- it "should call the method it describes" do
33
+ context "AVAILABLE_ATTRIBUTE_METHODS" do
34
+ SimpleModel::Attributes::ClassMethods::AVAILABLE_ATTRIBUTE_METHODS.each do |m,options|
35
+ it "should respond to #{m}" do
36
+ TestInit.respond_to?(m).should be_true
37
+ end
38
+ it "should respond to alias #{options[:alias]}" do
39
+ TestInit.respond_to?(options[:alias]).should be_true
40
+ end
41
+ end
42
+ end
43
+
44
+ context '#has_attribute' do
45
+ before(:all) do
47
46
  class TestDefault
48
47
  include SimpleModel::Attributes
49
- attr_accessor :test
50
- define_reader_with_options :test, :default => :default_value
48
+ has_attribute :foo, :default => "foo", :allow_blank => false
49
+ has_attribute :bar, :default => :default_value
50
+ has_attribute :fab, :default => :some_symbol
51
+ has_attribute :hop, :default => :default_hop, :allow_blank => false
52
+ has_attribute :tip, :default => "2", :initialize => false, :allow_blank => false
53
+ has_attribute :nap
54
+ has_attribute :my_array, :default => []
51
55
  def default_value
52
- "test"
56
+ "bar"
57
+ end
58
+
59
+ def default_hop
60
+ "hop" if nap
53
61
  end
54
62
  end
55
-
56
- default = TestDefault.new
57
- default.test.should eql("test")
58
63
  end
59
- end
60
-
64
+
65
+ before(:each) do
66
+ @default = TestDefault.new
67
+ end
61
68
 
62
- end
63
- describe SimpleModel::Attributes, 'has_booleans' do
64
- before(:all) do
65
- class TestBoolean
66
- include SimpleModel::Attributes
67
- has_booleans :test
69
+ it "should define setter method" do
70
+ @default.respond_to?(:foo=).should be_true
71
+ end
72
+
73
+ it "should define reader/getter method" do
74
+ @default.respond_to?(:foo).should be_true
75
+ end
76
+
77
+ context ':initialize => false' do
78
+ it "should not initialize with the default value" do
79
+ @default.attributes[:tip].should be_nil
80
+ @default.tip.should eql("2")
81
+ end
82
+ context "allow_blank => false"do
83
+ it "should not initialize, but should set the value on get" do
84
+ @default.attributes[:tip].should be_nil
85
+ @default.tip.should eql("2")
86
+ end
87
+ end
68
88
  end
89
+
90
+ it "should call the method it describe by the default value if it exists" do
91
+ @default.attributes[:bar].should eql("bar")
92
+ end
93
+
94
+ it "should set the defaul to the supplied symbol, if the method does not exist" do
95
+ @default.attributes[:fab].should eql(:some_symbol)
96
+ end
97
+
98
+ it "should allow default value to be an empty array" do
99
+ @default.my_array.should eql([])
100
+ end
101
+
102
+ it "should create a boolean? method for each attribute" do
103
+ @default.respond_to?(:foo?).should be_true
104
+ end
105
+
106
+ it "should return !blank?" do
107
+ @default.my_array.should eql([]) # blank array
108
+ @default.my_array?.should be_false
109
+ @default.my_array << 1
110
+ @default.my_array?.should be_true
111
+ end
112
+
113
+ it "should not allow blank if set" do
114
+ @default.foo.should eql("foo")
115
+ @default.foo = ""
116
+ @default.foo.should eql("foo")
117
+ @default.foo = "not blank"
118
+ @default.foo.should eql("not blank")
119
+ end
120
+
121
+ it "should try for the default if its blank on get" do
122
+ @default.hop.blank?.should be_true
123
+ @default.nap = "yep"
124
+ @default.hop.should eql("hop")
125
+ end
126
+
127
+
69
128
  end
70
-
71
- it "should add setter=, getter and getter? methods" do
72
- methods = TestBoolean.new.methods
73
- union = methods | [:test, :test=, :test?]
74
- union.should eql(methods)
129
+
130
+ context "on get" do
131
+ it "should perform on_get when set" do
132
+ class OnGet
133
+ include SimpleModel::Attributes
134
+ has_attribute :foo, :on_get => lambda{|obj,attr| (attr.blank? ? obj.send(:foo_default) : attr)}
135
+
136
+ def foo_default
137
+ "test"
138
+ end
139
+ end
140
+
141
+ new = OnGet.new
142
+ new.foo.should eql("test")
143
+ new.foo = "foo"
144
+ new.foo.should eql("foo")
145
+ end
75
146
  end
76
-
77
- end
78
- describe SimpleModel::Attributes, 'has_attributes' do
79
- before(:all) do
80
- class TestBoolean
81
- include SimpleModel::Attributes
82
- has_attributes :my_array, :default => []
147
+
148
+ context 'if supplied value can be cast' do
149
+ it "should throw an exception" do
150
+ class TestThrow
151
+ include SimpleModel::Attributes
152
+ has_booleans :boo
153
+ end
154
+
155
+ lambda{TestThrow.new(:boo => [])}.should raise_error(SimpleModel::ArgumentError)
83
156
  end
157
+
84
158
  end
85
-
86
- it "should allow default value to be an empty array" do
87
- test = TestBoolean.new
88
- test.my_array.should eql([])
159
+
160
+
161
+ after(:all) do
162
+ Object.send(:remove_const,:TestThrow)
163
+ Object.send(:remove_const,:OnGet)
164
+ Object.send(:remove_const,:TestDefault)
165
+ Object.send(:remove_const,:TestInit)
89
166
  end
90
-
91
- end
92
-
167
+ end