valuable 0.6 → 0.8
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 +169 -0
- data/lib/valuable.rb +110 -85
- data/rakefile.rb +76 -193
- data/test/bad_attributes_test.rb +23 -23
- data/test/deprecated_test.rb +80 -0
- data/test/inheritance_test.rb +28 -0
- data/test/valuable_test.rb +28 -16
- metadata +10 -18
- data/README.txt +0 -79
- data/lib/boolean.rb +0 -2
data/README.markdown
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
Introducing Valuable
|
2
|
+
====================
|
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.
|
5
|
+
|
6
|
+
Valuable provides DRY decoration like attr_accessor, but includes default values, light weight type casting and a constructor that accepts an attributes hash. It provides a class-level list of attributes, an instance-level attributes hash, and more.
|
7
|
+
|
8
|
+
Examples
|
9
|
+
-------
|
10
|
+
|
11
|
+
_basic syntax_
|
12
|
+
|
13
|
+
class Fruit
|
14
|
+
has_value :name
|
15
|
+
has_collection :vitamins
|
16
|
+
end
|
17
|
+
|
18
|
+
_constructor accepts an attributes hash_
|
19
|
+
|
20
|
+
>> apple = Fruit.new(:name => 'Apple')
|
21
|
+
|
22
|
+
>> apple.name
|
23
|
+
=> 'Apple'
|
24
|
+
|
25
|
+
>> apple.vitamins
|
26
|
+
=> []
|
27
|
+
|
28
|
+
_default values_
|
29
|
+
|
30
|
+
class Developer
|
31
|
+
has_value :name
|
32
|
+
has_value :nickname, :default => 'mort'
|
33
|
+
end
|
34
|
+
|
35
|
+
>> dev = Developer.new(:name => 'zk')
|
36
|
+
|
37
|
+
>> dev.name
|
38
|
+
=> 'zk'
|
39
|
+
|
40
|
+
>> dev.nickname
|
41
|
+
=> 'mort'
|
42
|
+
|
43
|
+
_setting a value to nil overrides the default._
|
44
|
+
|
45
|
+
>> Developer.new(:name => 'KDD', :nickname => nil).nickname
|
46
|
+
=> nil
|
47
|
+
|
48
|
+
_light weight type casting_
|
49
|
+
|
50
|
+
class BaseballPlayer < Valuable
|
51
|
+
|
52
|
+
has_value :at_bats, :klass => :integer
|
53
|
+
has_value :hits, :klass => :integer
|
54
|
+
|
55
|
+
def average
|
56
|
+
hits/at_bats.to_f if hits && at_bats
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
>> joe = BaseballPlayer.new(:hits => '5', :at_bats => '20', :on_drugs => '0' == '1')
|
61
|
+
|
62
|
+
>> joe.at_bats
|
63
|
+
=> 20
|
64
|
+
|
65
|
+
>> joe.average
|
66
|
+
=> 0.25
|
67
|
+
|
68
|
+
_I find myself using classes to format things... ( PhoneNumber is provided in `/examples` )_
|
69
|
+
|
70
|
+
class School < Valuable
|
71
|
+
has_value :name
|
72
|
+
has_value :phone, :klass => PhoneNumber
|
73
|
+
end
|
74
|
+
|
75
|
+
>> School.new(:name => 'Vanderbilt', :phone => '3332223333').phone
|
76
|
+
=> '(333) 222-3333'
|
77
|
+
|
78
|
+
_as a presenter in Rails_
|
79
|
+
|
80
|
+
class CalenderPresenter < Valuable
|
81
|
+
has_value :month, :klass => Integer, :default => Time.now.month
|
82
|
+
has_value :year, :klass => Integer, :default => Time.now.year
|
83
|
+
|
84
|
+
def start_date
|
85
|
+
Date.civil( year, month, 1)
|
86
|
+
end
|
87
|
+
|
88
|
+
def end_date
|
89
|
+
Date.civil( year, month, -1) #strange I know
|
90
|
+
end
|
91
|
+
|
92
|
+
def events
|
93
|
+
Event.find(:all, :conditions => event_conditions)
|
94
|
+
end
|
95
|
+
|
96
|
+
def event_conditions
|
97
|
+
['starts_at between ? and ?', start_date, end_date]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
_this class might appear in a controller like this:_
|
102
|
+
|
103
|
+
class CalendarController < ApplicationController
|
104
|
+
def show
|
105
|
+
@presenter = CalendarPresenter.new(params[:calendar])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
_but it's easier to understand like this:_
|
110
|
+
|
111
|
+
>> @presenter = CalendarPresenter.new({}) # first pageload
|
112
|
+
|
113
|
+
>> @presenter.start_date
|
114
|
+
=> Tue, 01 Dec 2009
|
115
|
+
|
116
|
+
>> @presenter.end_date
|
117
|
+
=> Thu, 31 Dec 2009
|
118
|
+
|
119
|
+
>> # User selects some other month and year; the next request looks like...
|
120
|
+
|
121
|
+
>> @presenter = CalendarPresenter.new({:month => '2', :year => '2002'})
|
122
|
+
|
123
|
+
>> @presenter.start_date
|
124
|
+
=> Fri, 01 Feb 2002
|
125
|
+
|
126
|
+
>> @presenter.end_date
|
127
|
+
=> Thu, 28 Feb 2002
|
128
|
+
|
129
|
+
...
|
130
|
+
|
131
|
+
So, if you're reading this, you're probably thinking, "I could have done that!" Yes, it's true. I'll happily agree that it's a relatively simple tool if you'll agree that it lets you model a calendar with an intuitive syntax, prevents you from writing yet another obvious constructor, and allows you to keep your brain focused on your app.
|
132
|
+
|
133
|
+
_you can access the attributes via the attributes hash. Only default and specified attributes will have entries here._
|
134
|
+
|
135
|
+
class Person < Valuable
|
136
|
+
has_value :name
|
137
|
+
has_value :is_developer, :default => false
|
138
|
+
has_value :ssn
|
139
|
+
end
|
140
|
+
|
141
|
+
>> elvis = Person.new(:name => 'The King')
|
142
|
+
|
143
|
+
>> elvis.attributes
|
144
|
+
=> {:name=>"The King", :is_developer=>false}
|
145
|
+
|
146
|
+
>> elvis.attributes[:name]
|
147
|
+
=> "The King"
|
148
|
+
|
149
|
+
>> elvis.ssn
|
150
|
+
=> nil
|
151
|
+
|
152
|
+
_also, you can get a list of all the defined attributes from the class_
|
153
|
+
|
154
|
+
>> Person.attributes
|
155
|
+
=> [:name, :is_developer, :ssn]
|
156
|
+
|
157
|
+
Default Values
|
158
|
+
--------------
|
159
|
+
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.
|
160
|
+
|
161
|
+
When a default value and a klass are specified, the default value will NOT be cast to type klass -- you must do it.
|
162
|
+
|
163
|
+
If a value having a default is set to null after it is constructed, it will NOT be set to the default.
|
164
|
+
|
165
|
+
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.
|
166
|
+
|
167
|
+
KLASS-ification
|
168
|
+
---------------
|
169
|
+
`: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`.
|
data/lib/valuable.rb
CHANGED
@@ -1,40 +1,48 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# This is the base class from which all classes that intend to use
|
4
|
-
# Valuable should inherit.
|
1
|
+
# Valuable is the class from which all classes (who are so inclined)
|
2
|
+
# should inherit.
|
5
3
|
#
|
6
|
-
# Example:
|
4
|
+
# ==Example:
|
7
5
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
6
|
+
# class Bus < Valuable
|
7
|
+
#
|
8
|
+
# has_value :number, :klass => :integer
|
9
|
+
# has_value :color, :default => 'yellow'
|
10
|
+
# has_collection :riders
|
11
|
+
#
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# >> Bus.attributes
|
15
|
+
# => [:number, :color, :riders]
|
16
|
+
# >> bus = Bus.new(:number => '3', :riders => ['GOF', 'Fowler', 'Mort']
|
17
|
+
# >> bus.attributes
|
18
|
+
# => {:number => 3, :riders => ['GOF', 'Fowler', 'Mort'], :color => 'yellow'}
|
13
19
|
class Valuable
|
14
20
|
|
15
|
-
# Returns a Hash
|
16
|
-
# either because they had a default value or because they were set in
|
17
|
-
# the constructor or after instanciation. Values that have not been defined
|
18
|
-
# and which have no default value will not appear in this collection.
|
21
|
+
# Returns a Hash representing all known values. Values are set three ways:
|
19
22
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
+
# (1) a default value
|
24
|
+
# (2) they were passed to the constructor
|
25
|
+
# Bus.new(:color => 'green')
|
26
|
+
# (3) they were set via their namesake setter
|
27
|
+
# bus.color = 'green'
|
28
|
+
#
|
29
|
+
# Values that have not been set and have no default not appear in this
|
30
|
+
# collection. Their namesake attribute methods will respond with nil.
|
31
|
+
# Always use symbols to access these values.
|
23
32
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
33
|
+
# >> bus = Bus.new(:number => 16) # color has default value 'yellow'
|
34
|
+
# >> bus.attributes
|
35
|
+
# => {:color => 'yellow', :number => 16}
|
27
36
|
def attributes
|
28
|
-
@attributes ||=
|
37
|
+
@attributes ||= deep_duplicate_of(self.class.defaults)
|
29
38
|
end
|
30
39
|
|
31
|
-
# accepts
|
32
|
-
# for this class.
|
33
|
-
def initialize(atts =
|
34
|
-
atts.each { |name, value| __send__("#{name}=", value ) }
|
40
|
+
# accepts an optional hash that will be used to populate the
|
41
|
+
# predefined attributes for this class.
|
42
|
+
def initialize(atts = nil)
|
43
|
+
atts.each { |name, value| __send__("#{name}=", value ) } if atts
|
35
44
|
end
|
36
45
|
|
37
|
-
# Creates a duplicate of all values.
|
38
46
|
def deep_duplicate_of(value)
|
39
47
|
Marshal.load(Marshal.dump(value))
|
40
48
|
end
|
@@ -49,92 +57,88 @@ class Valuable
|
|
49
57
|
# Returns a name/value set of the values that will be used on
|
50
58
|
# instanciation unless new values are provided.
|
51
59
|
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# >> Bus.defaults
|
57
|
-
# => {:color => 'yellow'}
|
58
|
-
#
|
60
|
+
# >> Bus.defaults
|
61
|
+
# => {:color => 'yellow'}
|
59
62
|
def defaults
|
60
63
|
@defaults ||= {}
|
61
64
|
end
|
62
65
|
|
63
|
-
# Decorator method that
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
66
|
+
# Decorator method that lets you specify the attributes for your
|
67
|
+
# model. It accepts an attribute name (a symbol) and an options
|
68
|
+
# hash. Valid options are :default, :klass and (when :klass is
|
69
|
+
# Boolean) :negative.
|
70
|
+
#
|
71
|
+
# :default - for the given attribute, use this value if no other
|
72
|
+
# is provided.
|
67
73
|
#
|
68
|
-
#
|
69
|
-
#
|
74
|
+
# :klass - light weight type casting. Use :integer, :string or
|
75
|
+
# :boolean. Alternately, supply a class.
|
70
76
|
#
|
71
|
-
# :
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
77
|
+
# When a :klassified attribute is set to some new value, if the value
|
78
|
+
# is not nil and is not already of that class, the value will be cast
|
79
|
+
# to the specified klass. In the case of :integer, it wil be done via
|
80
|
+
# .to_i. In the case of a random other class, it will be done via
|
81
|
+
# Class.new(value). If the value is nil, it will not be cast.
|
75
82
|
#
|
76
|
-
# A
|
83
|
+
# A good example: PhoneNumber < String is useful if you
|
77
84
|
# want numbers to come out the other end properly formatted, when your
|
78
85
|
# input may come in as an integer, or string without formatting, or
|
79
86
|
# string with bad formatting.
|
87
|
+
#
|
88
|
+
# IMPORTANT EXCEPTION
|
89
|
+
#
|
90
|
+
# Due to the way Rails handles checkboxes, '0' resolves to FALSE,
|
91
|
+
# though it would normally resolve to TRUE.
|
80
92
|
def has_value(name, options={})
|
93
|
+
|
94
|
+
name = name.to_sym
|
95
|
+
|
81
96
|
attributes << name
|
82
97
|
|
83
98
|
defaults[name] = options[:default] unless options[:default].nil?
|
84
99
|
|
85
100
|
create_accessor_for(name)
|
86
|
-
create_question_for(name) if options[:klass] ==
|
87
|
-
create_negative_question_for(name, options[:negative]) if options[:klass] ==
|
101
|
+
create_question_for(name) if options[:klass] == :boolean
|
102
|
+
create_negative_question_for(name, options[:negative]) if options[:klass] == :boolean && options[:negative]
|
88
103
|
|
89
104
|
create_setter_for(name, options[:klass], options[:default])
|
90
105
|
|
91
106
|
check_options_validity(name, options)
|
92
107
|
end
|
93
108
|
|
94
|
-
# This method returns an array of symbols, which are the only allowed
|
95
|
-
# options for has_value.
|
96
|
-
def known_options
|
97
|
-
[:klass, :default, :negative]
|
98
|
-
end
|
99
|
-
|
100
|
-
# validates option hashes passed to has_value
|
101
|
-
def check_options_validity(name, options)
|
102
|
-
invalid_options = options.keys - known_options
|
103
|
-
|
104
|
-
raise ArgumentError, "has_value did not know how to respond to #{invalid_options.join(', ')}. Valid (optional) arguments are: #{known_options.join(', ')}" unless invalid_options.empty?
|
105
|
-
end
|
106
|
-
|
107
109
|
# Creates the method that sets the value of an attribute. This setter
|
108
110
|
# is called both by the constructor. The constructor handles type
|
109
111
|
# casting. Setting values via the attributes hash avoids the method
|
110
112
|
# defined here.
|
111
113
|
def create_setter_for(name, klass, default)
|
112
|
-
|
113
|
-
|
114
|
+
|
115
|
+
case klass
|
116
|
+
when NilClass
|
117
|
+
|
114
118
|
define_method "#{name}=" do |value|
|
115
119
|
attributes[name] = value
|
116
120
|
end
|
117
121
|
|
118
|
-
|
122
|
+
when :integer
|
119
123
|
|
120
124
|
define_method "#{name}=" do |value|
|
121
125
|
value_as_integer = value && value.to_i
|
122
126
|
attributes[name] = value_as_integer
|
123
127
|
end
|
124
128
|
|
125
|
-
|
129
|
+
when :string
|
126
130
|
|
127
131
|
define_method "#{name}=" do |value|
|
128
132
|
value_as_string = value && value.to_s
|
129
133
|
attributes[name] = value_as_string
|
130
134
|
end
|
131
135
|
|
132
|
-
|
136
|
+
when :boolean
|
133
137
|
|
134
138
|
define_method "#{name}=" do |value|
|
135
|
-
attributes[name] = !!value
|
139
|
+
attributes[name] = value == '0' ? false : !!value
|
136
140
|
end
|
137
|
-
|
141
|
+
|
138
142
|
else
|
139
143
|
|
140
144
|
define_method "#{name}=" do |value|
|
@@ -160,13 +164,13 @@ class Valuable
|
|
160
164
|
# In addition to the normal getter and setter, boolean attributes
|
161
165
|
# get a method appended with a ?.
|
162
166
|
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
167
|
+
# class Player < Valuable
|
168
|
+
# has_value :free_agent, :klass => Boolean
|
169
|
+
# end
|
166
170
|
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
#
|
171
|
+
# juan = Player.new(:free_agent => true)
|
172
|
+
# >> juan.free_agent?
|
173
|
+
# => true
|
170
174
|
def create_question_for(name)
|
171
175
|
define_method "#{name}?" do
|
172
176
|
attributes[name]
|
@@ -175,13 +179,13 @@ class Valuable
|
|
175
179
|
|
176
180
|
# In some situations, the opposite of a value may be just as interesting.
|
177
181
|
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
182
|
+
# class Coder < Valuable
|
183
|
+
# has_value :agilist, :klass => Boolean, :negative => :waterfaller
|
184
|
+
# end
|
181
185
|
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
186
|
+
# monkey = Coder.new(:agilist => false)
|
187
|
+
# >> monkey.waterfaller?
|
188
|
+
# => true
|
185
189
|
def create_negative_question_for(name, negative)
|
186
190
|
define_method "#{negative}?" do
|
187
191
|
!attributes[name]
|
@@ -191,18 +195,39 @@ class Valuable
|
|
191
195
|
# this is a more intuitive way of marking an attribute as holding a
|
192
196
|
# collection.
|
193
197
|
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
198
|
+
# class Bus < Valuable
|
199
|
+
# has_value :riders, :default => [] # meh...
|
200
|
+
# has_collection :riders # better!
|
201
|
+
# end
|
197
202
|
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
#
|
203
|
+
# >> bus = Bus.new
|
204
|
+
# >> bus.riders << 'jack'
|
205
|
+
# >> bus.riders
|
206
|
+
# => ['jack']
|
202
207
|
def has_collection(name)
|
203
208
|
has_value(name, :default => [] )
|
204
209
|
end
|
205
210
|
|
211
|
+
private
|
212
|
+
|
213
|
+
def inherited(child)
|
214
|
+
attributes.each {|att| child.attributes << att }
|
215
|
+
defaults.each {|(name, value)| child.defaults[name] = value }
|
216
|
+
end
|
217
|
+
|
218
|
+
def known_options
|
219
|
+
[:klass, :default, :negative]
|
220
|
+
end
|
221
|
+
|
222
|
+
# this helper raises an exception if the options passed to has_value
|
223
|
+
# are wrong. Mostly written because I occasionally used :class instead
|
224
|
+
# of :klass and, being a moron, wasted time trying to find the issue.
|
225
|
+
def check_options_validity(name, options)
|
226
|
+
invalid_options = options.keys - known_options
|
227
|
+
|
228
|
+
raise ArgumentError, "has_value did not know how to respond to option(s) #{invalid_options.join(', ')}. Valid (optional) arguments are: #{known_options.join(', ')}" unless invalid_options.empty?
|
229
|
+
end
|
230
|
+
|
206
231
|
end
|
207
232
|
|
208
233
|
end
|
data/rakefile.rb
CHANGED
@@ -1,193 +1,76 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
|
4
|
-
require 'rake
|
5
|
-
require 'rake/
|
6
|
-
require 'rake/
|
7
|
-
require 'rake/
|
8
|
-
require 'rake/
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
t.
|
21
|
-
t.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
temp_files
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
rdoc.
|
41
|
-
rdoc.options << '--
|
42
|
-
rdoc.
|
43
|
-
rdoc.rdoc_files.include('
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
s.
|
49
|
-
s.
|
50
|
-
s.
|
51
|
-
s.
|
52
|
-
|
53
|
-
|
54
|
-
s.
|
55
|
-
s.
|
56
|
-
s.
|
57
|
-
|
58
|
-
s.
|
59
|
-
|
60
|
-
s.
|
61
|
-
s.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
task :publish => [:pdoc, :rubyforge_upload]
|
78
|
-
|
79
|
-
desc "Publish the release files to RubyForge."
|
80
|
-
task :rubyforge_upload => :package do
|
81
|
-
files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
82
|
-
|
83
|
-
if RUBY_FORGE_PROJECT then
|
84
|
-
require 'net/http'
|
85
|
-
require 'open-uri'
|
86
|
-
|
87
|
-
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
|
88
|
-
project_data = open(project_uri) { |data| data.read }
|
89
|
-
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
90
|
-
raise "Couldn't get group id" unless group_id
|
91
|
-
|
92
|
-
# This echos password to shell which is a bit sucky
|
93
|
-
if ENV["RUBY_FORGE_PASSWORD"]
|
94
|
-
password = ENV["RUBY_FORGE_PASSWORD"]
|
95
|
-
else
|
96
|
-
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
|
97
|
-
password = STDIN.gets.chomp
|
98
|
-
end
|
99
|
-
|
100
|
-
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
101
|
-
data = [
|
102
|
-
"login=1",
|
103
|
-
"form_loginname=#{RUBY_FORGE_USER}",
|
104
|
-
"form_pw=#{password}"
|
105
|
-
].join("&")
|
106
|
-
http.post("/account/login.php", data)
|
107
|
-
end
|
108
|
-
|
109
|
-
cookie = login_response["set-cookie"]
|
110
|
-
raise "Login failed" unless cookie
|
111
|
-
headers = { "Cookie" => cookie }
|
112
|
-
|
113
|
-
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
114
|
-
release_data = open(release_uri, headers) { |data| data.read }
|
115
|
-
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
116
|
-
raise "Couldn't get package id" unless package_id
|
117
|
-
|
118
|
-
first_file = true
|
119
|
-
release_id = ""
|
120
|
-
|
121
|
-
files.each do |filename|
|
122
|
-
basename = File.basename(filename)
|
123
|
-
file_ext = File.extname(filename)
|
124
|
-
file_data = File.open(filename, "rb") { |file| file.read }
|
125
|
-
|
126
|
-
puts "Releasing #{basename}..."
|
127
|
-
|
128
|
-
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
129
|
-
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
130
|
-
type_map = {
|
131
|
-
".zip" => "3000",
|
132
|
-
".tgz" => "3110",
|
133
|
-
".gz" => "3110",
|
134
|
-
".gem" => "1400"
|
135
|
-
}; type_map.default = "9999"
|
136
|
-
type = type_map[file_ext]
|
137
|
-
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
138
|
-
|
139
|
-
query_hash = if first_file then
|
140
|
-
{
|
141
|
-
"group_id" => group_id,
|
142
|
-
"package_id" => package_id,
|
143
|
-
"release_name" => PKG_FILE_NAME,
|
144
|
-
"release_date" => release_date,
|
145
|
-
"type_id" => type,
|
146
|
-
"processor_id" => "8000", # Any
|
147
|
-
"release_notes" => "",
|
148
|
-
"release_changes" => "",
|
149
|
-
"preformatted" => "1",
|
150
|
-
"submit" => "1"
|
151
|
-
}
|
152
|
-
else
|
153
|
-
{
|
154
|
-
"group_id" => group_id,
|
155
|
-
"release_id" => release_id,
|
156
|
-
"package_id" => package_id,
|
157
|
-
"step2" => "1",
|
158
|
-
"type_id" => type,
|
159
|
-
"processor_id" => "8000", # Any
|
160
|
-
"submit" => "Add This File"
|
161
|
-
}
|
162
|
-
end
|
163
|
-
|
164
|
-
query = "?" + query_hash.map do |(name, value)|
|
165
|
-
[name, URI.encode(value)].join("=")
|
166
|
-
end.join("&")
|
167
|
-
|
168
|
-
data = [
|
169
|
-
"--" + boundary,
|
170
|
-
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
171
|
-
"Content-Type: application/octet-stream",
|
172
|
-
"Content-Transfer-Encoding: binary",
|
173
|
-
"", file_data, ""
|
174
|
-
].join("\x0D\x0A")
|
175
|
-
|
176
|
-
release_headers = headers.merge(
|
177
|
-
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
178
|
-
)
|
179
|
-
|
180
|
-
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
181
|
-
http.post(target + query, data, release_headers)
|
182
|
-
end
|
183
|
-
|
184
|
-
if first_file then
|
185
|
-
release_id = release_response.body[/release_id=(\d+)/, 1]
|
186
|
-
raise("Couldn't get release id") unless release_id
|
187
|
-
end
|
188
|
-
|
189
|
-
first_file = false
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'config.rb'
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'rake/packagetask'
|
8
|
+
require 'rake/gempackagetask'
|
9
|
+
require 'rake/contrib/rubyforgepublisher'
|
10
|
+
|
11
|
+
task :default => [:test]
|
12
|
+
|
13
|
+
PKG_FILE_NAME = "#{CONFIG[:name]}-#{CONFIG[:version]}"
|
14
|
+
RUBY_FORGE_PROJECT = 'valuable'
|
15
|
+
RUBY_FORGE_USER = 'mustmodify'
|
16
|
+
|
17
|
+
desc "Run unit tests"
|
18
|
+
Rake::TestTask.new("test") { |t|
|
19
|
+
t.pattern = 'test/*_test.rb'
|
20
|
+
t.verbose = true
|
21
|
+
t.warning = true
|
22
|
+
}
|
23
|
+
|
24
|
+
desc 'clean temporary files, rdoc, and gem package'
|
25
|
+
task :clean => [:clobber_package, :clobber_rdoc] do
|
26
|
+
temp_filenames = File.join('**', '*.*~')
|
27
|
+
temp_files = Dir.glob(temp_filenames)
|
28
|
+
if temp_files.empty?
|
29
|
+
puts 'no temp files to delete'
|
30
|
+
else
|
31
|
+
puts "deleting #{temp_files.size} temp files"
|
32
|
+
end
|
33
|
+
|
34
|
+
File.delete(*temp_files)
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'Generate documentation for the Valuable plugin'
|
38
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
39
|
+
rdoc.title = 'Valuable - light weight modeling'
|
40
|
+
rdoc.options << '--line-numbers'
|
41
|
+
rdoc.options << '--inline-source'
|
42
|
+
rdoc.rdoc_files.include('README.markdown')
|
43
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
|
+
end
|
45
|
+
|
46
|
+
spec = Gem::Specification.new do |s|
|
47
|
+
s.name = CONFIG[:name]
|
48
|
+
s.version = CONFIG[:version]
|
49
|
+
s.platform = Gem::Platform::RUBY
|
50
|
+
s.summary = 'attr_accessor on steroids with defaults, constructor, and light casting.'
|
51
|
+
s.description = "Valuable is a ruby base class that is essentially attr_accessor on steroids. It intends to use a simple and intuitive interface, allowing you to get on with the logic specific to your application."
|
52
|
+
|
53
|
+
s.files = FileList["{lib, test, examples}/**/*"].to_a + %w( README.markdown rakefile.rb )
|
54
|
+
s.require_path = 'lib'
|
55
|
+
s.test_files = FileList["{test}/**/*test.rb"].to_a
|
56
|
+
s.has_rdoc = true
|
57
|
+
|
58
|
+
s.rubyforge_project = RUBY_FORGE_PROJECT
|
59
|
+
s.author = 'Johnathon Wright'
|
60
|
+
s.email = 'jw@mustmodify.com'
|
61
|
+
s.homepage = 'http://www.github.com/mustmodify/valuable'
|
62
|
+
end
|
63
|
+
|
64
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
65
|
+
#pkg.need_zip = true
|
66
|
+
#pkg.need_tar = true
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "Publish the API documentation"
|
70
|
+
task :pdoc => [:rdoc] do
|
71
|
+
Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload
|
72
|
+
end
|
73
|
+
|
74
|
+
desc 'Publish the gem and API docs'
|
75
|
+
task :publish => [:pdoc, :rubyforge_upload]
|
76
|
+
|
data/test/bad_attributes_test.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'valuable.rb'
|
5
|
-
require 'mocha'
|
6
|
-
|
7
|
-
class Infrastructure < Valuable
|
8
|
-
end
|
9
|
-
|
10
|
-
class BadAttributesTest < Test::Unit::TestCase
|
11
|
-
|
12
|
-
def test_that_has_value_grumbles_when_it_gets_bad_attributes
|
13
|
-
assert_raises ArgumentError do
|
14
|
-
Infrastructure.has_value :fu, :invalid => 'shut your mouth'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_that_valid_arguments_cause_no_grumbling
|
19
|
-
assert_nothing_raised do
|
20
|
-
Infrastructure.has_value :bar, :klass => Integer
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'valuable.rb'
|
5
|
+
require 'mocha'
|
6
|
+
|
7
|
+
class Infrastructure < Valuable
|
8
|
+
end
|
9
|
+
|
10
|
+
class BadAttributesTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_that_has_value_grumbles_when_it_gets_bad_attributes
|
13
|
+
assert_raises ArgumentError do
|
14
|
+
Infrastructure.has_value :fu, :invalid => 'shut your mouth'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_that_valid_arguments_cause_no_grumbling
|
19
|
+
assert_nothing_raised do
|
20
|
+
Infrastructure.has_value :bar, :klass => Integer
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'valuable.rb'
|
5
|
+
require 'mocha'
|
6
|
+
|
7
|
+
class Signature < String
|
8
|
+
end
|
9
|
+
|
10
|
+
class Cube < String
|
11
|
+
def initialize(number)
|
12
|
+
super "Lives in Cube #{number}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class DevCertifications < Valuable
|
17
|
+
has_value :a_plus, :default => false
|
18
|
+
has_value :mcts, :default => false
|
19
|
+
has_value :hash_rocket, :default => false
|
20
|
+
end
|
21
|
+
|
22
|
+
class Dev < Valuable
|
23
|
+
has_value :has_exposure_to_sunlight, :default => false
|
24
|
+
has_value :mindset
|
25
|
+
has_value :name, :default => 'DHH Jr.', :klass => String
|
26
|
+
has_value :signature, :klass => Signature
|
27
|
+
has_value :cubical, :klass => Cube
|
28
|
+
has_value :hacker, :default => true
|
29
|
+
has_value :certifications, :default => DevCertifications.new
|
30
|
+
has_value :quote
|
31
|
+
|
32
|
+
has_collection :favorite_gems
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# Previously, we used :klass => Klass instead of :klass => :klass.
|
37
|
+
# I decided it was just plain dirty. On refactoring, I realized that
|
38
|
+
# most it would continue to work. Other stuff, unfortunately, would
|
39
|
+
# break horribly. (Integer.new, for instance, makes Ruby very angry.)
|
40
|
+
# The purpose of these tests is to verify that everything _either_
|
41
|
+
# breaks horribly or works, where the third option is fails silently
|
42
|
+
# and mysteriously.
|
43
|
+
class DeprecatedTest < Test::Unit::TestCase
|
44
|
+
|
45
|
+
def test_that_attributes_can_be_klassified
|
46
|
+
dev = Dev.new(:signature => 'brah brah')
|
47
|
+
assert_equal Signature, dev.signature.class
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_that_randomly_classed_attributes_persist_nils
|
51
|
+
assert_equal nil, Dev.new.signature
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_that_randomly_classed_attributes_respect_defaults
|
55
|
+
assert_equal 'DHH Jr.', Dev.new.name
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_that_constructor_casts_attributes
|
59
|
+
assert_equal 'Lives in Cube 20', Dev.new(:cubical => 20).cubical
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_that_setter_casts_attributes
|
63
|
+
golden_boy = Dev.new
|
64
|
+
golden_boy.cubical = 20
|
65
|
+
|
66
|
+
assert_equal 'Lives in Cube 20', golden_boy.cubical
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_that_properly_klassed_values_are_not_rekast
|
70
|
+
why_hammer = Signature.new('go ask your mom')
|
71
|
+
Signature.expects(:new).with(why_hammer).never
|
72
|
+
hammer = Dev.new(:signature => why_hammer)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_that_default_values_can_be_set_to_nothing
|
76
|
+
assert_equal nil, Dev.new(:hacker => nil).hacker
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'valuable.rb'
|
5
|
+
require 'mocha'
|
6
|
+
|
7
|
+
class Parent < Valuable
|
8
|
+
has_value :name, :default => 'unknown'
|
9
|
+
end
|
10
|
+
|
11
|
+
class Child < Parent
|
12
|
+
has_value :age
|
13
|
+
end
|
14
|
+
|
15
|
+
class InheritanceTest < Test::Unit::TestCase
|
16
|
+
|
17
|
+
def test_that_children_inherit_their_parents_attributes
|
18
|
+
assert Child.attributes.include?(:name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_that_children_have_distinctive_attributes
|
22
|
+
assert Child.attributes.include?(:age)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_that_parents_do_not_inherit_things_from_children
|
26
|
+
assert_equal [:name], Parent.attributes
|
27
|
+
end
|
28
|
+
end
|
data/test/valuable_test.rb
CHANGED
@@ -4,9 +4,6 @@ require 'test/unit'
|
|
4
4
|
require 'valuable.rb'
|
5
5
|
require 'mocha'
|
6
6
|
|
7
|
-
class Signature < String
|
8
|
-
end
|
9
|
-
|
10
7
|
class Cubical < String
|
11
8
|
def initialize(number)
|
12
9
|
super "Lives in Cubical #{number}"
|
@@ -20,17 +17,16 @@ class DevCertifications < Valuable
|
|
20
17
|
end
|
21
18
|
|
22
19
|
class Developer < Valuable
|
23
|
-
has_value :experience, :klass =>
|
20
|
+
has_value :experience, :klass => :integer
|
24
21
|
has_value :has_exposure_to_sunlight, :default => false
|
25
22
|
has_value :mindset
|
26
|
-
has_value :name, :default => 'DHH Jr.', :klass =>
|
27
|
-
has_value :
|
28
|
-
has_value :snacks_per_day, :klass => Integer, :default => 7
|
23
|
+
has_value :name, :default => 'DHH Jr.', :klass => :string
|
24
|
+
has_value :snacks_per_day, :klass => :integer, :default => 7
|
29
25
|
has_value :cubical, :klass => Cubical
|
30
26
|
has_value :hacker, :default => true
|
31
|
-
has_value :certifications, :default => DevCertifications.new
|
27
|
+
has_value :certifications, :klass => DevCertifications, :default => DevCertifications.new
|
32
28
|
has_value :quote
|
33
|
-
has_value :employed, :klass =>
|
29
|
+
has_value :employed, :klass => :boolean, :negative => 'unemployed'
|
34
30
|
|
35
31
|
has_collection :favorite_gems
|
36
32
|
|
@@ -71,8 +67,8 @@ class BaseTest < Test::Unit::TestCase
|
|
71
67
|
end
|
72
68
|
|
73
69
|
def test_that_attributes_can_be_klassified
|
74
|
-
dev = Developer.new(:
|
75
|
-
assert_equal
|
70
|
+
dev = Developer.new(:cubical => 12)
|
71
|
+
assert_equal Cubical, dev.cubical.class
|
76
72
|
end
|
77
73
|
|
78
74
|
def test_that_defaults_appear_in_attributes_hash
|
@@ -84,7 +80,7 @@ class BaseTest < Test::Unit::TestCase
|
|
84
80
|
end
|
85
81
|
|
86
82
|
def test_that_randomly_classed_attributes_persist_nils
|
87
|
-
assert_equal nil, Developer.new.
|
83
|
+
assert_equal nil, Developer.new.cubical
|
88
84
|
end
|
89
85
|
|
90
86
|
def test_that_randomly_classed_attributes_respect_defaults
|
@@ -103,7 +99,7 @@ class BaseTest < Test::Unit::TestCase
|
|
103
99
|
end
|
104
100
|
|
105
101
|
def test_that_attributes_are_available_as_class_method
|
106
|
-
assert Developer.attributes.include?(:
|
102
|
+
assert Developer.attributes.include?(:cubical)
|
107
103
|
end
|
108
104
|
|
109
105
|
def test_that_a_model_can_have_a_collection
|
@@ -143,9 +139,9 @@ class BaseTest < Test::Unit::TestCase
|
|
143
139
|
end
|
144
140
|
|
145
141
|
def test_that_properly_klassed_values_are_not_rekast
|
146
|
-
|
147
|
-
|
148
|
-
|
142
|
+
stapler = Cubical.new('in sub-basement')
|
143
|
+
Cubical.expects(:new).with(stapler).never
|
144
|
+
Developer.new(:cubical => stapler)
|
149
145
|
end
|
150
146
|
|
151
147
|
def test_that_values_can_be_set_to_false
|
@@ -168,6 +164,10 @@ class BaseTest < Test::Unit::TestCase
|
|
168
164
|
assert_equal false, Developer.new(:employed => nil).employed
|
169
165
|
end
|
170
166
|
|
167
|
+
def test_that_string_zero_becomes_false
|
168
|
+
assert_equal false, Developer.new(:employed => '0').employed
|
169
|
+
end
|
170
|
+
|
171
171
|
def test_that_boolean_values_get_questionmarked_methods
|
172
172
|
assert Developer.instance_methods.include?('employed?')
|
173
173
|
end
|
@@ -179,4 +179,16 @@ class BaseTest < Test::Unit::TestCase
|
|
179
179
|
def test_that_negative_methods_are_negative
|
180
180
|
assert_equal true, Developer.new(:employed => false).unemployed?
|
181
181
|
end
|
182
|
+
|
183
|
+
def test_that_constructor_can_handle_an_instance_of_nothing
|
184
|
+
assert_nothing_raised do
|
185
|
+
Developer.new(nil)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_that_klassification_does_not_break_when_stringified
|
190
|
+
assert_nothing_raised do
|
191
|
+
Developer.new(:experience => '2')
|
192
|
+
end
|
193
|
+
end
|
182
194
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: valuable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.8"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johnathon Wright
|
@@ -9,20 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-16 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: "0"
|
24
|
-
version:
|
25
|
-
description: Valuable is a ruby base class that is essentially attr_accessor on steroids. Its aim is to provide Rails-like goodness where ActiveRecord isn't an option. It intends to use a simple and intuitive interface, allowing you to get on with the logic specific to your application.
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Valuable is a ruby base class that is essentially attr_accessor on steroids. It intends to use a simple and intuitive interface, allowing you to get on with the logic specific to your application.
|
26
17
|
email: jw@mustmodify.com
|
27
18
|
executables: []
|
28
19
|
|
@@ -31,12 +22,11 @@ extensions: []
|
|
31
22
|
extra_rdoc_files: []
|
32
23
|
|
33
24
|
files:
|
34
|
-
- lib/boolean.rb
|
35
25
|
- lib/valuable.rb
|
36
|
-
- README.
|
26
|
+
- README.markdown
|
37
27
|
- rakefile.rb
|
38
28
|
has_rdoc: true
|
39
|
-
homepage: http://
|
29
|
+
homepage: http://www.github.com/mustmodify/valuable
|
40
30
|
licenses: []
|
41
31
|
|
42
32
|
post_install_message:
|
@@ -59,10 +49,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
49
|
requirements: []
|
60
50
|
|
61
51
|
rubyforge_project: valuable
|
62
|
-
rubygems_version: 1.3.
|
52
|
+
rubygems_version: 1.3.5
|
63
53
|
signing_key:
|
64
54
|
specification_version: 3
|
65
55
|
summary: attr_accessor on steroids with defaults, constructor, and light casting.
|
66
56
|
test_files:
|
67
57
|
- test/bad_attributes_test.rb
|
58
|
+
- test/deprecated_test.rb
|
59
|
+
- test/inheritance_test.rb
|
68
60
|
- test/valuable_test.rb
|
data/README.txt
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
|
2
|
-
=Introducing Valuable
|
3
|
-
|
4
|
-
Valuable is a ruby base class that is essentially attr_accessor on steroids. Its aim is to provide Rails-like goodness without the database. 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.
|
5
|
-
|
6
|
-
Valuable provides DRY decoration like attr_accessor, but includes default values, light weight type casting, a constructor that accepts an attributes hash, a class-level list of attributes, an instance-level attributes hash, and more.
|
7
|
-
|
8
|
-
==Example
|
9
|
-
|
10
|
-
class BaseballPlayer < Valuable
|
11
|
-
|
12
|
-
has_value :at_bats, :klass => Integer
|
13
|
-
has_value :hits, :klass => Integer
|
14
|
-
has_value :league, :default => 'unknown'
|
15
|
-
has_value :name, :dependency => true
|
16
|
-
has_value :cell, :klass => PhoneNumber, :default => 'Unknown'
|
17
|
-
has_value :active, :klass => Boolean
|
18
|
-
|
19
|
-
has_collection :teammates
|
20
|
-
|
21
|
-
def average
|
22
|
-
hits/at_bats.to_f if hits && at_bats
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
joe = BaseballPlayer.new(:name => 'Joe', :hits => 5, :at_bats => 20, :cell => '1234567890')
|
28
|
-
|
29
|
-
joe.at_bats
|
30
|
-
|
31
|
-
20
|
32
|
-
|
33
|
-
joe.active?
|
34
|
-
|
35
|
-
nil
|
36
|
-
|
37
|
-
joe.league
|
38
|
-
|
39
|
-
'unknown'
|
40
|
-
|
41
|
-
joe.average
|
42
|
-
|
43
|
-
0.25
|
44
|
-
|
45
|
-
joe.at_bats = nil
|
46
|
-
|
47
|
-
joe.average
|
48
|
-
|
49
|
-
nil
|
50
|
-
|
51
|
-
joe.teammates
|
52
|
-
|
53
|
-
[]
|
54
|
-
|
55
|
-
joe.cell
|
56
|
-
|
57
|
-
'(123) 456-7890'
|
58
|
-
|
59
|
-
joe.cell = nil
|
60
|
-
|
61
|
-
joe.cell
|
62
|
-
|
63
|
-
nil
|
64
|
-
|
65
|
-
==DEFAULT VALUES
|
66
|
-
|
67
|
-
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.
|
68
|
-
|
69
|
-
When a default value and a klass are specified, the default value will NOT be cast to type klass -- you must do it. See "jersey" example above.
|
70
|
-
|
71
|
-
If a value having a default is set to null after it is constructed, it will NOT be set to the default.
|
72
|
-
|
73
|
-
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.
|
74
|
-
|
75
|
-
==KLASS-ification
|
76
|
-
|
77
|
-
Boolean is defined as a module in lib for uniformity.
|
78
|
-
|
79
|
-
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.
|
data/lib/boolean.rb
DELETED