valuable 0.9.1 → 0.9.2

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.
data/README.markdown CHANGED
@@ -1,31 +1,65 @@
1
1
  Introducing Valuable
2
2
  ====================
3
3
 
4
- Valuable enables quick modeling... it's attr_accessor on steroids. It intends to use a simple and intuitive interface, allowing you easily create models without hassles, so you can get on with the logic specific to your application. I find myself using it in sort of a presenter capacity, when I have to pull data from non-standard data sources, and to handle temporary data during imports.
4
+ Valuable enables quick modeling... it's attr_accessor on steroids. For all those times you wanted to use OO to model something but it seemed like too much of a pain, try Valuable. Its simple interface allows you to model without hassles, so you can get on with the logic specific to your application.
5
5
 
6
- Valuable provides DRY decoration like attr_accessor, but includes default values and other formatting, and a constructor that accepts an attributes hash. It provides a class-level list of attributes, an instance-level attributes hash, and more.
6
+ Frequent Uses:
7
+
8
+ **pre-refactor modeling** to model a class you want to abstract but know would be a pain... as in, "I would love to pull Appointment out of this WorkOrder class, but since that isn't going to happen soon, let me quickly create WorkOrder.appointments... I can then create Appointment\#to\_s, appointment.end_time, appointment.duration, etc. I can use that to facilitate emitting XML or doing something with views, rather than polluting WorkOrder with appointment-related logic."
9
+
10
+ **as a presenter** as in, "I need to take in a few different models to generate this map... I need a class that models the integration, but I don't need to persist that to a database."
11
+
12
+ **creating models from non-standard data sources** to keep data from non-standard data sources in memory during an import or to render data from an API call.
13
+
14
+ Valuable provides DRY decoration like attr_accessor, but includes default values and other formatting (like, "2" => 2), and a constructor that accepts an attributes hash. It provides a class-level list of attributes, an instance-level attributes hash, and more.
7
15
 
8
16
  Type Casting in Ruby? You must be crazy...
9
17
  -------------------------------------------------------------
10
18
  Yeah, I get that alot. I mean, about type casting. I'm not writing
11
- C# over here. In fact, I'm going to start using the euphamism
19
+ C# over here. Rails does it, they just don't call it type casting,
20
+ so no one complains when they pass in "2" as a parameter and mysteriously
21
+ it ends up as an integer. In fact, I'm going to start using the euphamism
12
22
  'Formatting' just so people will stop looking at me that way.
13
23
 
14
- Say you have get some data from a web service via JSON.
15
- Parse the json and you get this:
24
+ Say you're getting information for a directory from a web service via JSON:
25
+
26
+ class Person < Valuable
27
+ has_value :name
28
+ has_value :age, :klass => :integer
29
+ has_value :phone_number, :klass => PhoneNumber
30
+ # see /examples/phone_number.rb
31
+
32
+ 'person' =>
33
+ 'name' => 'Mr. Freud',
34
+ 'age' => "344",
35
+ 'phone_number' => '8002195642',
36
+ 'specialization_code' => "2106"
37
+
38
+ you'll end up with this:
39
+
40
+ >> p = Person.new(params[:person])
41
+
42
+ >> p.age
43
+ => 344
44
+
45
+ >> p.phone_number
46
+ => (337) 326-3121
47
+
48
+ >> p.phone_number.class
49
+ => PhoneNumber
50
+
51
+ "Yeah, I could have just done that myself."
52
+ "Right, but now you don't have to."
16
53
 
17
- 'person' =>
18
- 'name' => 'Mr. Freud',
19
- 'phone_number' => '8002195642',
20
- 'specialization_code' => 2106
54
+ Default Values
55
+ --------------
56
+ Default values are used when no value is provided to the constructor. If the value nil is provided, nil will be used instead of the default.
21
57
 
22
- then parse it:
58
+ When a default value and a klass are specified, the default value will NOT be cast to type klass -- you must do it.
23
59
 
24
- class Person < Valuable
25
- has_value :name, :default => 'Unknown'
26
- has_value :phone_number
60
+ If a value having a default is set to null after it is constructed, it will NOT be set to the default.
27
61
 
28
-
62
+ If there is no default value, the result will be nil, EVEN if type casting is provided. Thus, a field typically cast as an Integer can be nil. See calculation of average.
29
63
 
30
64
  Examples
31
65
  -------
@@ -67,7 +101,7 @@ _setting a value to nil overrides the default._
67
101
  >> Developer.new(:name => 'KDD', :nickname => nil).nickname
68
102
  => nil
69
103
 
70
- _light weight type casting_
104
+ _formatting aka light-weight type-casting_
71
105
 
72
106
  class BaseballPlayer < Valuable
73
107
 
@@ -87,6 +121,59 @@ _light weight type casting_
87
121
  >> joe.average
88
122
  => 0.25
89
123
 
124
+ # Currently supports:
125
+ # - integer
126
+ # - decimal ( casts to BigDecimal... NOTE: nil remains nil, not 0 as in nil.to_i )
127
+ # - string
128
+ # - boolean ( NOTE: '0' casts to FALSE... I would be fascinated to know when this is not the correct behavior. )
129
+ # - or any class ( formats as SomeClass.new( ) unless value.is_a?( SomeClass ) )
130
+
131
+
132
+ _collections_
133
+
134
+ class MailingList < Valuable
135
+ has_collection :emails
136
+ end
137
+
138
+ >> m = MailingList.new
139
+
140
+ >> m.emails
141
+ => []
142
+
143
+ >> m = MailingList.new(:emails => [ 'johnathon.e.wright@nasa.gov', 'other.people@wherever.com' ])
144
+
145
+ => m.emails
146
+ >> [ 'johnathon.e.wright@nasa.gov', 'other.people@wherever.com' ]
147
+
148
+ _formatting collections_
149
+
150
+ class Player < Valuable
151
+ has_value :first_name
152
+ has_value :last_name
153
+ has_value :salary
154
+ end
155
+
156
+ class Team < Valuable
157
+ has_value :name
158
+ has_value :long_name
159
+
160
+ has_collection :players, :klass => Player
161
+ end
162
+
163
+ t = Team.new(:name => 'Toronto', :long_name => 'The Toronto Blue Jays',
164
+ 'players' => [
165
+ {'first_name' => 'Chad', 'last_name' => 'Beck', :salary => 'n/a'},
166
+ {'first_name' => 'Shawn', 'last_name' => 'Camp', :salary => '2250000'},
167
+ {'first_name' => 'Brett', 'last_name' => 'Cecil', :salary => '443100'},
168
+ Player.new(:first_name => 'Travis', :last_name => 'Snider', :salary => '435800')
169
+ ])
170
+
171
+ >> t.players.first
172
+ => #<Player:0x7fa51e4a1da0 @attributes={:salary=>"n/a", :first_name=>"Chad", :last_name=>"Beck"}>
173
+
174
+ >> t.players.last
175
+ => #<Player:0x7fa51ea6a9f8 @attributes={:salary=>"435800", :first_name=>"Travis", :last_name=>"Snider"}>
176
+
90
177
  _aliases_
91
178
 
92
179
  # This example requires active_support because of Hash.from_xml
@@ -97,22 +184,12 @@ _aliases_
97
184
 
98
185
  >> xml = '<software><Title>Windows XP</Title></software>'
99
186
 
100
- >> xp = Software.new(:Title => Hash.from_xml(xml)['software'])
187
+ >> xp = Software.new(Hash.from_xml(xml)['software'])
101
188
 
102
189
  >> xp.name
103
190
  => "Windows XP"
104
191
 
105
192
 
106
- _I find myself using classes to format things... ( PhoneNumber is provided in `/examples` )_
107
-
108
- class School < Valuable
109
- has_value :name
110
- has_value :phone, :klass => PhoneNumber
111
- end
112
-
113
- >> School.new(:name => 'Vanderbilt', :phone => '3332223333').phone
114
- => '(333) 222-3333'
115
-
116
193
  _as a presenter in Rails_
117
194
 
118
195
  class CalenderPresenter < Valuable
@@ -130,13 +207,13 @@ _as a presenter in Rails_
130
207
  def events
131
208
  Event.find(:all, :conditions => event_conditions)
132
209
  end
133
-
210
+
134
211
  def event_conditions
135
212
  ['starts_at between ? and ?', start_date, end_date]
136
213
  end
137
214
  end
138
215
 
139
- _this class might appear in a controller like this:_
216
+ this class might appear in a controller like this:
140
217
 
141
218
  class CalendarController < ApplicationController
142
219
  def show
@@ -144,7 +221,7 @@ _this class might appear in a controller like this:_
144
221
  end
145
222
  end
146
223
 
147
- _but it's easier to understand like this:_
224
+ but it's easier to understand like this:
148
225
 
149
226
  >> @presenter = CalendarPresenter.new({}) # first pageload
150
227
 
@@ -155,7 +232,7 @@ _but it's easier to understand like this:_
155
232
  => Thu, 31 Dec 2009
156
233
 
157
234
  >> # User selects some other month and year; the next request looks like...
158
-
235
+
159
236
  >> @presenter = CalendarPresenter.new({:month => '2', :year => '2002'})
160
237
 
161
238
  >> @presenter.start_date
@@ -179,7 +256,7 @@ _you can access the attributes via the attributes hash. Only default and specifi
179
256
  >> elvis = Person.new(:name => 'The King')
180
257
 
181
258
  >> elvis.attributes
182
- => {:name=>"The King", :is_developer=>false}
259
+ => {:name=>"The King", :is_developer=>false}
183
260
 
184
261
  >> elvis.attributes[:name]
185
262
  => "The King"
@@ -188,20 +265,8 @@ _you can access the attributes via the attributes hash. Only default and specifi
188
265
  => nil
189
266
 
190
267
  _also, you can get a list of all the defined attributes from the class_
191
-
268
+
192
269
  >> Person.attributes
193
270
  => [:name, :is_developer, :ssn]
194
271
 
195
- Default Values
196
- --------------
197
- Default values are used when no value is provided to the constructor. If the value nil is provided, nil will be used instead of the default.
198
-
199
- When a default value and a klass are specified, the default value will NOT be cast to type klass -- you must do it.
200
-
201
- If a value having a default is set to null after it is constructed, it will NOT be set to the default.
202
-
203
- If there is no default value, the result will be nil, EVEN if type casting is provided. Thus, a field typically cast as an Integer can be nil. See calculation of average.
204
272
 
205
- KLASS-ification
206
- ---------------
207
- `:integer`, `:string` and `:boolean` use `to_i`, `to_s` and `!!` respectively. All other klasses use `klass.new(value)` unless the value `is_a?(klass)`, in which case it is unmolested. Nils are never klassified. In the example above, hits, which is an integer, is `nil` if not set, rather than `nil.to_i = 0`.
@@ -1,3 +1,5 @@
1
+ # Trying to extract as much logic as possible to minimize the memory
2
+ # footprint of individual instances. Feedback welcome.
1
3
  require 'bigdecimal'
2
4
 
3
5
  module Valuable::Utils
@@ -17,7 +19,7 @@ module Valuable::Utils
17
19
  Marshal.load(Marshal.dump(value))
18
20
  end
19
21
 
20
- def cast( name, value, attributes, collection_item = false )
22
+ def format( name, value, attributes, collection_item = false )
21
23
  klass = collection_item ? attributes[name][:item_klass] : attributes[name][:klass]
22
24
 
23
25
  case klass
@@ -28,7 +30,7 @@ module Valuable::Utils
28
30
  when :collection
29
31
  if( value.kind_of?(Array) )
30
32
  out = value.map do |item|
31
- Valuable::Utils.cast( name, item, attributes, true )
33
+ Valuable::Utils.format( name, item, attributes, true )
32
34
  end
33
35
  end
34
36
 
data/lib/valuable.rb CHANGED
@@ -87,7 +87,7 @@ class Valuable
87
87
  attribute = Valuable::Utils.find_attribute_for( name, self.class._attributes )
88
88
 
89
89
  if attribute
90
- self.attributes[attribute] = Valuable::Utils.cast(attribute, value, self.class._attributes)
90
+ self.attributes[attribute] = Valuable::Utils.format(attribute, value, self.class._attributes)
91
91
  else
92
92
  raise( ArgumentError, "#{self.class.to_s} does not have an attribute or alias '#{name}'", caller) unless self.permissive?
93
93
  end
data/test/typical_test.rb CHANGED
@@ -3,7 +3,7 @@ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
3
3
  require 'test/unit'
4
4
  require 'valuable.rb'
5
5
  require 'date'
6
- require File.dirname(__FILE__) + '/../examples/phone_number'
6
+ require File.expand_path(File.dirname(__FILE__) + '/../examples/phone_number')
7
7
  class Person < Valuable
8
8
  has_value :dob, :klass => :date
9
9
  end
@@ -169,11 +169,11 @@ class BaseTest < Test::Unit::TestCase
169
169
  end
170
170
 
171
171
  def test_that_boolean_values_get_questionmarked_methods
172
- assert Developer.instance_methods.include?('employed?')
172
+ assert Developer.instance_methods.map(&:to_sym).include?(:employed?)
173
173
  end
174
174
 
175
175
  def test_that_boolean_values_get_negative_methods
176
- assert Developer.instance_methods.include?('unemployed?')
176
+ assert Developer.instance_methods.map(&:to_sym).include?(:unemployed?)
177
177
  end
178
178
 
179
179
  def test_that_negative_methods_are_negative
data/todo.txt CHANGED
@@ -1,10 +1,3 @@
1
- Find some way to do
2
-
3
- has_value :something, :klass => Decimal
4
-
5
- * must handle BigDecimal not being around
6
-
7
-
8
1
  - has_value :start_date, :default => {Date.today}
9
2
  - has_value :price, :default => 50, :extend => MoneyFormatter
10
3
 
@@ -19,6 +12,17 @@ class SomeSearchThing < Valuable
19
12
 
20
13
  end
21
14
 
15
+ class Datum < Valuable
16
+ has_index :by_name
17
+ has_list :calculations
18
+ end
19
+ -or-
20
+ class Datum < Valuable
21
+ lists :calculations
22
+ indexes :by_name
23
+ end
24
+
25
+
22
26
  BEST PRACTICES DOC
23
27
 
24
28
  When creating a searcher:
@@ -74,18 +78,6 @@ like this:
74
78
  end
75
79
 
76
80
 
77
-
78
- :klass => :decimal
79
- - When is decimal available? Only load then.
80
- - If calling :decimal and it hasn't loaded, error
81
-
82
-
83
-
84
- class Change < Decimal
85
- extend Valuable::whatever or
86
- extend Valuable
87
-
88
- ...
89
- end
81
+ what about has_value :number, :construct => 'Decimal#parse'
90
82
 
91
83
  - do a better job with method_missing
data/valuable.version CHANGED
@@ -1 +1 @@
1
- 0.9.1
1
+ 0.9.2
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valuable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 57
4
+ hash: 63
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 1
10
- version: 0.9.1
9
+ - 2
10
+ version: 0.9.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Johnathon Wright
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-18 00:00:00 -05:00
18
+ date: 2011-09-27 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies: []
21
21