attributes1 5.0.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 +331 -0
- data/README.tmpl +133 -0
- data/a.rb +29 -0
- data/b.rb +47 -0
- data/gemspec.rb +28 -0
- data/gen_readme.rb +32 -0
- data/install.rb +206 -0
- data/lib/attributes-5.0.0.rb +118 -0
- data/lib/attributes.rb +118 -0
- data/samples/a.rb +21 -0
- data/samples/b.rb +22 -0
- data/samples/c.rb +12 -0
- data/samples/d.rb +34 -0
- data/samples/e.rb +18 -0
- data/samples/f.rb +21 -0
- metadata +59 -0
data/README
ADDED
@@ -0,0 +1,331 @@
|
|
1
|
+
NAME
|
2
|
+
attributes.rb
|
3
|
+
|
4
|
+
INSTALL
|
5
|
+
gem install attributes
|
6
|
+
|
7
|
+
URIS
|
8
|
+
http://codeforpeople.com/lib/ruby
|
9
|
+
http://rubyforge.org/projects/codeforpeople/
|
10
|
+
http://codeforpeople.rubyforge.org/svn/
|
11
|
+
|
12
|
+
SYNOPSIS
|
13
|
+
attributes.rb provides a set of attr_* like method with several user
|
14
|
+
friendly additions. attributes.rb is similar to the traits.rb package but
|
15
|
+
sacrifices a few features for simplicity of implementation.
|
16
|
+
|
17
|
+
the implementation of attributes.rb borrows many of the best ideas from the
|
18
|
+
metakoans.rb ruby quiz
|
19
|
+
|
20
|
+
http://www.rubyquiz.com/quiz67.html
|
21
|
+
|
22
|
+
in particular the solutions of Christian Neukirchen and Florian Gross along
|
23
|
+
with concepts from the original traits lib
|
24
|
+
|
25
|
+
key features provided by attributes are
|
26
|
+
|
27
|
+
- ability to specify default values for attrs and definition time. values
|
28
|
+
can be literal objects or blocks, which are evaluated in the context of
|
29
|
+
self to initialize the variable
|
30
|
+
|
31
|
+
- classes remember which attributes they've defined and this information is
|
32
|
+
available to client code
|
33
|
+
|
34
|
+
- a whole suite of methods is defined by calls to #attributes including
|
35
|
+
getter, setter, query (var?) and banger (var! - which forces
|
36
|
+
re-initialization from the default value)
|
37
|
+
|
38
|
+
- ability to define multiple attributes at once using key => value pairs
|
39
|
+
|
40
|
+
- fast lookup of whether or not a class has defined a certain attribute
|
41
|
+
|
42
|
+
- attributes can be defined on objects on a per singleton basis as well
|
43
|
+
|
44
|
+
- getters acts as setters if an argument is given to them
|
45
|
+
|
46
|
+
- block caching, calling an attribute with a block sets the instance
|
47
|
+
variable to that block
|
48
|
+
|
49
|
+
all this in < 100 lines of code
|
50
|
+
|
51
|
+
HISTORY
|
52
|
+
5.0.1
|
53
|
+
- removed wrong dep on pervasives from gemspec.rb
|
54
|
+
|
55
|
+
5.0.0
|
56
|
+
- added support for block caching. for example
|
57
|
+
|
58
|
+
- simple block caching:
|
59
|
+
|
60
|
+
class Filter
|
61
|
+
attribute :process
|
62
|
+
end
|
63
|
+
|
64
|
+
filter = Filter.new
|
65
|
+
|
66
|
+
filter.process{|line| line.upcase}
|
67
|
+
|
68
|
+
lines.each do |line|
|
69
|
+
p filter.process.call(line)
|
70
|
+
end
|
71
|
+
|
72
|
+
- using block caching to delay block evaluation/class-factory:
|
73
|
+
|
74
|
+
module MigrationDSL
|
75
|
+
attribute :migration
|
76
|
+
|
77
|
+
def migration_class
|
78
|
+
model = self
|
79
|
+
|
80
|
+
Class.new(::ActiveRecord::Migration) do
|
81
|
+
singleton_class =
|
82
|
+
class << self
|
83
|
+
self
|
84
|
+
end
|
85
|
+
singleton_class.module_eval{ attribute :model => model }
|
86
|
+
singleton_class.module_eval &model.migration
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Table < ActiveRecord::Base
|
92
|
+
extend MigrationDSL
|
93
|
+
end
|
94
|
+
|
95
|
+
class Jobs < Table
|
96
|
+
migration do
|
97
|
+
def up
|
98
|
+
create_table model.table_name, :primary_key => model.primary_key do |t|
|
99
|
+
t.column 'vinyl_shoes', :text
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def down
|
104
|
+
create_table model.table_name
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
...
|
110
|
+
|
111
|
+
JobsMigration = Jobs.migration_class
|
112
|
+
|
113
|
+
4.1.0
|
114
|
+
- 4.0.0 introduced a bug where a query (foo?) would not initialize a var -
|
115
|
+
4.1.0 fixes that
|
116
|
+
|
117
|
+
4.0.0
|
118
|
+
- removed dependancy on, and bundle of, pervasives
|
119
|
+
- faster. as fast as normal method definition.
|
120
|
+
- faster lookup for MyClass.attributes.include?('foobar')
|
121
|
+
|
122
|
+
3.7.0
|
123
|
+
small patch to use 'instance_variable_defined?' instead of defined?
|
124
|
+
keyword
|
125
|
+
|
126
|
+
3.5.0
|
127
|
+
migrated to a pervasives based impl to attributes should work on any
|
128
|
+
object - even blankslate objects
|
129
|
+
|
130
|
+
3.3.0
|
131
|
+
|
132
|
+
moved to an instance variable-less model using an module level closure for
|
133
|
+
the attributes list
|
134
|
+
|
135
|
+
SAMPLES
|
136
|
+
|
137
|
+
<========< samples/a.rb >========>
|
138
|
+
|
139
|
+
~ > cat samples/a.rb
|
140
|
+
|
141
|
+
#
|
142
|
+
# basic usage is like attr, but note that attribute defines a suite of methods
|
143
|
+
#
|
144
|
+
require 'attributes'
|
145
|
+
|
146
|
+
class C
|
147
|
+
attribute 'a'
|
148
|
+
end
|
149
|
+
|
150
|
+
c = C.new
|
151
|
+
|
152
|
+
c.a = 42
|
153
|
+
p c.a #=> 42
|
154
|
+
p 'forty-two' if c.a? #=> 'forty-two'
|
155
|
+
|
156
|
+
#
|
157
|
+
# attributes works on object too
|
158
|
+
#
|
159
|
+
o = Object.new
|
160
|
+
o.attribute 'answer' => 42
|
161
|
+
p o.answer #=> 42
|
162
|
+
|
163
|
+
~ > ruby samples/a.rb
|
164
|
+
|
165
|
+
42
|
166
|
+
"forty-two"
|
167
|
+
42
|
168
|
+
|
169
|
+
|
170
|
+
<========< samples/b.rb >========>
|
171
|
+
|
172
|
+
~ > cat samples/b.rb
|
173
|
+
|
174
|
+
#
|
175
|
+
# default values may be given either directly or as a block which will be
|
176
|
+
# evaluated in the context of self. in both cases (value or block) the
|
177
|
+
# default is set only once and only if needed - it's a lazy evaluation. the
|
178
|
+
# 'banger' method can be used to re-initialize a variable at any point whether
|
179
|
+
# or not it's already been initialized.
|
180
|
+
#
|
181
|
+
require 'attributes'
|
182
|
+
|
183
|
+
class C
|
184
|
+
attribute :a => 42
|
185
|
+
attribute(:b){ Float a }
|
186
|
+
end
|
187
|
+
|
188
|
+
c = C.new
|
189
|
+
p c.a #=> 42
|
190
|
+
p c.b #=> 42.0
|
191
|
+
|
192
|
+
c.a = 43
|
193
|
+
p c.a #=> 43
|
194
|
+
c.a!
|
195
|
+
p c.a #=> 42
|
196
|
+
|
197
|
+
~ > ruby samples/b.rb
|
198
|
+
|
199
|
+
42
|
200
|
+
42.0
|
201
|
+
43
|
202
|
+
42
|
203
|
+
|
204
|
+
|
205
|
+
<========< samples/c.rb >========>
|
206
|
+
|
207
|
+
~ > cat samples/c.rb
|
208
|
+
|
209
|
+
#
|
210
|
+
# multiple values may by given, plain names and key/val pairs may be mixed.
|
211
|
+
#
|
212
|
+
require 'attributes'
|
213
|
+
|
214
|
+
class C
|
215
|
+
attributes 'x', 'y' => 0b101000, 'z' => 0b10
|
216
|
+
end
|
217
|
+
|
218
|
+
c = C.new
|
219
|
+
c.x = c.y + c.z
|
220
|
+
p c.x #=> 42
|
221
|
+
|
222
|
+
~ > ruby samples/c.rb
|
223
|
+
|
224
|
+
42
|
225
|
+
|
226
|
+
|
227
|
+
<========< samples/d.rb >========>
|
228
|
+
|
229
|
+
~ > cat samples/d.rb
|
230
|
+
|
231
|
+
#
|
232
|
+
# a nice feature is that all attributes are enumerated in the class. this,
|
233
|
+
# combined with the fact that the getter method is defined so as to delegate
|
234
|
+
# to the setter when an argument is given, means bulk initialization and/or
|
235
|
+
# attribute traversal is very easy.
|
236
|
+
#
|
237
|
+
require 'attributes'
|
238
|
+
|
239
|
+
class C
|
240
|
+
attributes %w( x y z )
|
241
|
+
|
242
|
+
def attributes
|
243
|
+
self.class.attributes
|
244
|
+
end
|
245
|
+
|
246
|
+
def initialize
|
247
|
+
attributes.each_with_index{|a,i| send a, i}
|
248
|
+
end
|
249
|
+
|
250
|
+
def to_hash
|
251
|
+
attributes.inject({}){|h,a| h.update a => send(a)}
|
252
|
+
end
|
253
|
+
|
254
|
+
def inspect
|
255
|
+
to_hash.inspect
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
c = C.new
|
260
|
+
p c.attributes
|
261
|
+
p c
|
262
|
+
|
263
|
+
c.x 'forty-two'
|
264
|
+
p c.x
|
265
|
+
|
266
|
+
~ > ruby samples/d.rb
|
267
|
+
|
268
|
+
["x", "y", "z"]
|
269
|
+
{"x"=>0, "y"=>1, "z"=>2}
|
270
|
+
"forty-two"
|
271
|
+
|
272
|
+
|
273
|
+
<========< samples/e.rb >========>
|
274
|
+
|
275
|
+
~ > cat samples/e.rb
|
276
|
+
|
277
|
+
#
|
278
|
+
# my favourite element of attributes is that getters can also be setters.
|
279
|
+
# this allows incredibly clean looking code like
|
280
|
+
#
|
281
|
+
require 'attributes'
|
282
|
+
|
283
|
+
class Config
|
284
|
+
attributes %w( host port)
|
285
|
+
def initialize(&block) instance_eval &block end
|
286
|
+
end
|
287
|
+
|
288
|
+
conf = Config.new{
|
289
|
+
host 'codeforpeople.org'
|
290
|
+
|
291
|
+
port 80
|
292
|
+
}
|
293
|
+
|
294
|
+
p conf
|
295
|
+
|
296
|
+
~ > ruby samples/e.rb
|
297
|
+
|
298
|
+
#<Config:0x1fb58 @port=80, @host="codeforpeople.org">
|
299
|
+
|
300
|
+
|
301
|
+
<========< samples/f.rb >========>
|
302
|
+
|
303
|
+
~ > cat samples/f.rb
|
304
|
+
|
305
|
+
#
|
306
|
+
# of course attributes works as well at class/module level as at instance
|
307
|
+
# level
|
308
|
+
#
|
309
|
+
require 'attributes'
|
310
|
+
|
311
|
+
module Logging
|
312
|
+
Level_names = {
|
313
|
+
0 => 'INFO',
|
314
|
+
# ...
|
315
|
+
42 => 'DEBUG',
|
316
|
+
}
|
317
|
+
|
318
|
+
class << self
|
319
|
+
attribute 'level' => 42
|
320
|
+
attribute('level_name'){ Level_names[level] }
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
p Logging.level
|
325
|
+
p Logging.level_name
|
326
|
+
|
327
|
+
~ > ruby samples/f.rb
|
328
|
+
|
329
|
+
42
|
330
|
+
"DEBUG"
|
331
|
+
|
data/README.tmpl
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
NAME
|
2
|
+
attributes.rb
|
3
|
+
|
4
|
+
INSTALL
|
5
|
+
gem install attributes
|
6
|
+
|
7
|
+
URIS
|
8
|
+
http://codeforpeople.com/lib/ruby
|
9
|
+
http://rubyforge.org/projects/codeforpeople/
|
10
|
+
http://codeforpeople.rubyforge.org/svn/
|
11
|
+
|
12
|
+
SYNOPSIS
|
13
|
+
attributes.rb provides a set of attr_* like method with several user
|
14
|
+
friendly additions. attributes.rb is similar to the traits.rb package but
|
15
|
+
sacrifices a few features for simplicity of implementation.
|
16
|
+
|
17
|
+
the implementation of attributes.rb borrows many of the best ideas from the
|
18
|
+
metakoans.rb ruby quiz
|
19
|
+
|
20
|
+
http://www.rubyquiz.com/quiz67.html
|
21
|
+
|
22
|
+
in particular the solutions of Christian Neukirchen and Florian Gross along
|
23
|
+
with concepts from the original traits lib
|
24
|
+
|
25
|
+
key features provided by attributes are
|
26
|
+
|
27
|
+
- ability to specify default values for attrs and definition time. values
|
28
|
+
can be literal objects or blocks, which are evaluated in the context of
|
29
|
+
self to initialize the variable
|
30
|
+
|
31
|
+
- classes remember which attributes they've defined and this information is
|
32
|
+
available to client code
|
33
|
+
|
34
|
+
- a whole suite of methods is defined by calls to #attributes including
|
35
|
+
getter, setter, query (var?) and banger (var! - which forces
|
36
|
+
re-initialization from the default value)
|
37
|
+
|
38
|
+
- ability to define multiple attributes at once using key => value pairs
|
39
|
+
|
40
|
+
- fast lookup of whether or not a class has defined a certain attribute
|
41
|
+
|
42
|
+
- attributes can be defined on objects on a per singleton basis as well
|
43
|
+
|
44
|
+
- getters acts as setters if an argument is given to them
|
45
|
+
|
46
|
+
- block caching, calling an attribute with a block sets the instance
|
47
|
+
variable to that block
|
48
|
+
|
49
|
+
all this in < 100 lines of code
|
50
|
+
|
51
|
+
HISTORY
|
52
|
+
5.0.0
|
53
|
+
- added support for block caching. for example
|
54
|
+
|
55
|
+
- simple block caching:
|
56
|
+
|
57
|
+
class Filter
|
58
|
+
attribute :process
|
59
|
+
end
|
60
|
+
|
61
|
+
filter = Filter.new
|
62
|
+
|
63
|
+
filter.process{|line| line.upcase}
|
64
|
+
|
65
|
+
lines.each do |line|
|
66
|
+
p filter.process.call(line)
|
67
|
+
end
|
68
|
+
|
69
|
+
- using block caching to delay block evaluation/class-factory:
|
70
|
+
|
71
|
+
module MigrationDSL
|
72
|
+
attribute :migration
|
73
|
+
|
74
|
+
def migration_class
|
75
|
+
model = self
|
76
|
+
|
77
|
+
Class.new(::ActiveRecord::Migration) do
|
78
|
+
singleton_class =
|
79
|
+
class << self
|
80
|
+
self
|
81
|
+
end
|
82
|
+
singleton_class.module_eval{ attribute :model => model }
|
83
|
+
singleton_class.module_eval &model.migration
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Table < ActiveRecord::Base
|
89
|
+
extend MigrationDSL
|
90
|
+
end
|
91
|
+
|
92
|
+
class Jobs < Table
|
93
|
+
migration do
|
94
|
+
def up
|
95
|
+
create_table model.table_name, :primary_key => model.primary_key do |t|
|
96
|
+
t.column 'vinyl_shoes', :text
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def down
|
101
|
+
create_table model.table_name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
...
|
107
|
+
|
108
|
+
JobsMigration = Jobs.migration_class
|
109
|
+
|
110
|
+
4.1.0
|
111
|
+
- 4.0.0 introduced a bug where a query (foo?) would not initialize a var -
|
112
|
+
4.1.0 fixes that
|
113
|
+
|
114
|
+
4.0.0
|
115
|
+
- removed dependancy on, and bundle of, pervasives
|
116
|
+
- faster. as fast as normal method definition.
|
117
|
+
- faster lookup for MyClass.attributes.include?('foobar')
|
118
|
+
|
119
|
+
3.7.0
|
120
|
+
small patch to use 'instance_variable_defined?' instead of defined?
|
121
|
+
keyword
|
122
|
+
|
123
|
+
3.5.0
|
124
|
+
migrated to a pervasives based impl to attributes should work on any
|
125
|
+
object - even blankslate objects
|
126
|
+
|
127
|
+
3.3.0
|
128
|
+
|
129
|
+
moved to an instance variable-less model using an module level closure for
|
130
|
+
the attributes list
|
131
|
+
|
132
|
+
SAMPLES
|
133
|
+
@samples
|
data/a.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'attributes'
|
2
|
+
|
3
|
+
module M
|
4
|
+
p(( attribute 'a' => 42 ))
|
5
|
+
p(( attribute('b'){ "forty-two (#{ self })" } ))
|
6
|
+
end
|
7
|
+
p M.attributes
|
8
|
+
p M.attributes.include?('a')
|
9
|
+
p M.attributes.include?('b')
|
10
|
+
p M.attributes.include?('c')
|
11
|
+
|
12
|
+
class C
|
13
|
+
include M
|
14
|
+
end
|
15
|
+
p C.new.a
|
16
|
+
p C.new.b
|
17
|
+
p C.attributes
|
18
|
+
p C.attributes.include?('a')
|
19
|
+
p C.attributes.include?('b')
|
20
|
+
p C.attributes.include?('c')
|
21
|
+
|
22
|
+
class B < C
|
23
|
+
end
|
24
|
+
p B.new.a
|
25
|
+
p B.new.b
|
26
|
+
p B.attributes
|
27
|
+
p B.attributes.include?('a')
|
28
|
+
p B.attributes.include?('b')
|
29
|
+
p B.attributes.include?('c')
|
data/b.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'lib/attributes.rb'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'active_record'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
options = YAML.load <<-txt
|
7
|
+
adapter: postgresql
|
8
|
+
database: votelink
|
9
|
+
username: www
|
10
|
+
host: localhost
|
11
|
+
encoding: UTF8
|
12
|
+
txt
|
13
|
+
ActiveRecord::Base.establish_connection options
|
14
|
+
|
15
|
+
module MigrationDSL
|
16
|
+
attribute :migration
|
17
|
+
|
18
|
+
def migration_class
|
19
|
+
model = self
|
20
|
+
Class.new(::ActiveRecord::Migration) do
|
21
|
+
singleton_class =
|
22
|
+
class << self
|
23
|
+
self
|
24
|
+
end
|
25
|
+
singleton_class.module_eval{ attribute :model => model }
|
26
|
+
singleton_class.module_eval &model.migration
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Table < ActiveRecord::Base
|
32
|
+
extend MigrationDSL
|
33
|
+
end
|
34
|
+
|
35
|
+
class Jobs < Table
|
36
|
+
migration do
|
37
|
+
def up
|
38
|
+
create_table model.table_name, :primary_key => model.primary_key do |t|
|
39
|
+
t.column 'rockin', :text
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def down
|
44
|
+
create_table model.table_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/gemspec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
Gem::Specification::new do |spec|
|
7
|
+
$VERBOSE = nil
|
8
|
+
lib = 'attributes'
|
9
|
+
spec.name = 'attributes1'
|
10
|
+
spec.version = version
|
11
|
+
spec.platform = Gem::Platform::RUBY
|
12
|
+
spec.summary = lib
|
13
|
+
|
14
|
+
spec.files = Dir::glob "**/**"
|
15
|
+
spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
|
16
|
+
|
17
|
+
spec.require_path = "lib"
|
18
|
+
spec.autorequire = lib
|
19
|
+
|
20
|
+
spec.has_rdoc = File::exist? "doc"
|
21
|
+
spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
|
22
|
+
#spec.add_dependency 'pervasives', '>= 1.0'
|
23
|
+
|
24
|
+
spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
|
25
|
+
|
26
|
+
spec.author = "Mitesh Jain"
|
27
|
+
spec.email = "mitijain123@gmail.com"
|
28
|
+
end
|
data/gen_readme.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
$VERBOSE=nil
|
4
|
+
|
5
|
+
def indent s, n = 2
|
6
|
+
ws = ' ' * n
|
7
|
+
s.gsub %r/^/, ws
|
8
|
+
end
|
9
|
+
|
10
|
+
template = IO::read 'README.tmpl'
|
11
|
+
|
12
|
+
samples = ''
|
13
|
+
prompt = '~ > '
|
14
|
+
|
15
|
+
Dir['sample*/*'] .each do |sample|
|
16
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
17
|
+
|
18
|
+
cmd = "cat #{ sample }"
|
19
|
+
samples << indent(prompt + cmd, 2) << "\n\n"
|
20
|
+
samples << indent(`#{ cmd }`, 4) << "\n"
|
21
|
+
|
22
|
+
cmd = "ruby #{ sample }"
|
23
|
+
samples << indent(prompt + cmd, 2) << "\n\n"
|
24
|
+
|
25
|
+
cmd = "ruby -Ilib #{ sample }"
|
26
|
+
samples << indent(`#{ cmd } 2>&1`, 4) << "\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
#samples.gsub! %r/^/, ' '
|
30
|
+
|
31
|
+
readme = template.gsub %r/^\s*@samples\s*$/, samples
|
32
|
+
print readme
|
data/install.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'find'
|
4
|
+
require 'ftools'
|
5
|
+
require 'tempfile'
|
6
|
+
include Config
|
7
|
+
|
8
|
+
LIBDIR = "lib"
|
9
|
+
LIBDIR_MODE = 0644
|
10
|
+
|
11
|
+
BINDIR = "bin"
|
12
|
+
BINDIR_MODE = 0755
|
13
|
+
|
14
|
+
|
15
|
+
$srcdir = CONFIG["srcdir"]
|
16
|
+
$version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
17
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", $version)
|
18
|
+
$archdir = File.join($libdir, CONFIG["arch"])
|
19
|
+
$site_libdir = $:.find {|x| x =~ /site_ruby$/}
|
20
|
+
$bindir = CONFIG["bindir"] || CONFIG['BINDIR']
|
21
|
+
$ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
|
22
|
+
$ruby_ext = CONFIG['EXEEXT'] || ''
|
23
|
+
$ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
|
24
|
+
|
25
|
+
if !$site_libdir
|
26
|
+
$site_libdir = File.join($libdir, "site_ruby")
|
27
|
+
elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
|
28
|
+
$site_libdir = File.join($site_libdir, $version)
|
29
|
+
end
|
30
|
+
|
31
|
+
def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
|
32
|
+
#{{{
|
33
|
+
path = []
|
34
|
+
dir = []
|
35
|
+
Find.find(srcdir) do |f|
|
36
|
+
next unless FileTest.file?(f)
|
37
|
+
next if (f = f[srcdir.length+1..-1]) == nil
|
38
|
+
next if (/CVS$/ =~ File.dirname(f))
|
39
|
+
next if f =~ %r/\.lnk/
|
40
|
+
path.push f
|
41
|
+
dir |= [File.dirname(f)]
|
42
|
+
end
|
43
|
+
for f in dir
|
44
|
+
next if f == "."
|
45
|
+
next if f == "CVS"
|
46
|
+
File::makedirs(File.join(destdir, f))
|
47
|
+
end
|
48
|
+
for f in path
|
49
|
+
next if (/\~$/ =~ f)
|
50
|
+
next if (/^\./ =~ File.basename(f))
|
51
|
+
unless bin
|
52
|
+
File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
|
53
|
+
else
|
54
|
+
from = File.join(srcdir, f)
|
55
|
+
to = File.join(destdir, f)
|
56
|
+
shebangify(from) do |sf|
|
57
|
+
$deferr.print from, " -> ", File::catname(from, to), "\n"
|
58
|
+
$deferr.printf "chmod %04o %s\n", mode, to
|
59
|
+
File::install(sf, to, mode, false)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
#}}}
|
64
|
+
end
|
65
|
+
def shebangify f
|
66
|
+
#{{{
|
67
|
+
open(f) do |fd|
|
68
|
+
buf = fd.read 42
|
69
|
+
if buf =~ %r/^\s*#\s*!.*ruby/o
|
70
|
+
ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
|
71
|
+
begin
|
72
|
+
fd.rewind
|
73
|
+
ftmp.puts "#!#{ $ruby }"
|
74
|
+
while((buf = fd.read(8192)))
|
75
|
+
ftmp.write buf
|
76
|
+
end
|
77
|
+
ftmp.close
|
78
|
+
yield ftmp.path
|
79
|
+
ensure
|
80
|
+
ftmp.close!
|
81
|
+
end
|
82
|
+
else
|
83
|
+
yield f
|
84
|
+
end
|
85
|
+
end
|
86
|
+
#}}}
|
87
|
+
end
|
88
|
+
def ARGV.switch
|
89
|
+
#{{{
|
90
|
+
return nil if self.empty?
|
91
|
+
arg = self.shift
|
92
|
+
return nil if arg == '--'
|
93
|
+
if arg =~ /^-(.)(.*)/
|
94
|
+
return arg if $1 == '-'
|
95
|
+
raise 'unknown switch "-"' if $2.index('-')
|
96
|
+
self.unshift "-#{$2}" if $2.size > 0
|
97
|
+
"-#{$1}"
|
98
|
+
else
|
99
|
+
self.unshift arg
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
#}}}
|
103
|
+
end
|
104
|
+
def ARGV.req_arg
|
105
|
+
#{{{
|
106
|
+
self.shift || raise('missing argument')
|
107
|
+
#}}}
|
108
|
+
end
|
109
|
+
def linkify d, linked = []
|
110
|
+
#--{{{
|
111
|
+
if test ?d, d
|
112
|
+
versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
|
113
|
+
versioned.each do |v|
|
114
|
+
src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
|
115
|
+
lnk = nil
|
116
|
+
begin
|
117
|
+
if test ?l, dst
|
118
|
+
lnk = "#{ dst }.lnk"
|
119
|
+
puts "#{ dst } -> #{ lnk }"
|
120
|
+
File::rename dst, lnk
|
121
|
+
end
|
122
|
+
unless test ?e, dst
|
123
|
+
puts "#{ src } -> #{ dst }"
|
124
|
+
File::copy src, dst
|
125
|
+
linked << dst
|
126
|
+
end
|
127
|
+
ensure
|
128
|
+
if lnk
|
129
|
+
at_exit do
|
130
|
+
puts "#{ lnk } -> #{ dst }"
|
131
|
+
File::rename lnk, dst
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
linked
|
138
|
+
#--}}}
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
#
|
143
|
+
# main program
|
144
|
+
#
|
145
|
+
|
146
|
+
libdir = $site_libdir
|
147
|
+
bindir = $bindir
|
148
|
+
no_linkify = false
|
149
|
+
linked = nil
|
150
|
+
help = false
|
151
|
+
|
152
|
+
usage = <<-usage
|
153
|
+
#{ File::basename $0 }
|
154
|
+
-d, --destdir <destdir>
|
155
|
+
-l, --libdir <libdir>
|
156
|
+
-b, --bindir <bindir>
|
157
|
+
-r, --ruby <ruby>
|
158
|
+
-n, --no_linkify
|
159
|
+
-s, --sudo
|
160
|
+
-h, --help
|
161
|
+
usage
|
162
|
+
|
163
|
+
begin
|
164
|
+
while switch = ARGV.switch
|
165
|
+
case switch
|
166
|
+
when '-d', '--destdir'
|
167
|
+
libdir = ARGV.req_arg
|
168
|
+
when '-l', '--libdir'
|
169
|
+
libdir = ARGV.req_arg
|
170
|
+
when '-b', '--bindir'
|
171
|
+
bindir = ARGV.req_arg
|
172
|
+
when '-r', '--ruby'
|
173
|
+
$ruby = ARGV.req_arg
|
174
|
+
when '-n', '--no_linkify'
|
175
|
+
no_linkify = true
|
176
|
+
when '-s', '--sudo'
|
177
|
+
sudo = 'sudo'
|
178
|
+
when '-h', '--help'
|
179
|
+
help = true
|
180
|
+
else
|
181
|
+
raise "unknown switch #{switch.dump}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
rescue
|
185
|
+
STDERR.puts $!.to_s
|
186
|
+
STDERR.puts usage
|
187
|
+
exit 1
|
188
|
+
end
|
189
|
+
|
190
|
+
if help
|
191
|
+
STDOUT.puts usage
|
192
|
+
exit
|
193
|
+
end
|
194
|
+
|
195
|
+
unless no_linkify
|
196
|
+
linked = linkify('lib') + linkify('bin')
|
197
|
+
end
|
198
|
+
|
199
|
+
system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
|
200
|
+
|
201
|
+
install_rb(LIBDIR, libdir, LIBDIR_MODE)
|
202
|
+
install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
|
203
|
+
|
204
|
+
if linked
|
205
|
+
linked.each{|path| File::rm_f path}
|
206
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Attributes
|
2
|
+
Attributes::VERSION = '5.0.0' unless defined? Attributes::VERSION
|
3
|
+
def self.version() Attributes::VERSION end
|
4
|
+
|
5
|
+
class List < ::Array
|
6
|
+
def << element
|
7
|
+
super
|
8
|
+
self
|
9
|
+
ensure
|
10
|
+
uniq!
|
11
|
+
index!
|
12
|
+
end
|
13
|
+
def index!
|
14
|
+
@index ||= Hash.new
|
15
|
+
each{|element| @index[element] = true}
|
16
|
+
end
|
17
|
+
def include? element
|
18
|
+
@index ||= Hash.new
|
19
|
+
@index[element] ? true : false
|
20
|
+
end
|
21
|
+
def initializers
|
22
|
+
@initializers ||= Hash.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def attributes *a, &b
|
27
|
+
unless a.empty?
|
28
|
+
returned = Hash.new
|
29
|
+
|
30
|
+
hashes, names = a.partition{|x| Hash === x}
|
31
|
+
names_and_defaults = {}
|
32
|
+
hashes.each{|h| names_and_defaults.update h}
|
33
|
+
names.flatten.compact.each{|name| names_and_defaults.update name => nil}
|
34
|
+
|
35
|
+
initializers = __attributes__.initializers
|
36
|
+
|
37
|
+
names_and_defaults.each do |name, default|
|
38
|
+
raise NameError, "bad instance variable name '@#{ name }'" if "@#{ name }" =~ %r/[!?=]$/o
|
39
|
+
name = name.to_s
|
40
|
+
|
41
|
+
initialize = b || lambda { default }
|
42
|
+
initializer = lambda do |this|
|
43
|
+
Object.instance_method('instance_eval').bind(this).call &initialize
|
44
|
+
end
|
45
|
+
initializer_id = initializer.object_id
|
46
|
+
__attributes__.initializers[name] = initializer
|
47
|
+
|
48
|
+
module_eval <<-code
|
49
|
+
def #{ name }=(*value, &block)
|
50
|
+
value.unshift block if block
|
51
|
+
@#{ name } = value.first
|
52
|
+
end
|
53
|
+
code
|
54
|
+
|
55
|
+
module_eval <<-code
|
56
|
+
def #{ name }(*value, &block)
|
57
|
+
value.unshift block if block
|
58
|
+
return self.send('#{ name }=', value.first) unless value.empty?
|
59
|
+
#{ name }! unless defined? @#{ name }
|
60
|
+
@#{ name }
|
61
|
+
end
|
62
|
+
code
|
63
|
+
|
64
|
+
module_eval <<-code
|
65
|
+
def #{ name }!
|
66
|
+
initializer = ObjectSpace._id2ref #{ initializer_id }
|
67
|
+
self.#{ name } = initializer.call(self)
|
68
|
+
@#{ name }
|
69
|
+
end
|
70
|
+
code
|
71
|
+
|
72
|
+
module_eval <<-code
|
73
|
+
def #{ name }?
|
74
|
+
#{ name }
|
75
|
+
end
|
76
|
+
code
|
77
|
+
|
78
|
+
attributes << name
|
79
|
+
returned[name] = initializer
|
80
|
+
end
|
81
|
+
|
82
|
+
returned
|
83
|
+
else
|
84
|
+
begin
|
85
|
+
__attribute_list__
|
86
|
+
rescue NameError
|
87
|
+
singleton_class =
|
88
|
+
class << self
|
89
|
+
self
|
90
|
+
end
|
91
|
+
klass = self
|
92
|
+
singleton_class.module_eval do
|
93
|
+
attribute_list = List.new
|
94
|
+
define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
|
95
|
+
alias_method '__attribute_list__', 'attribute_list'
|
96
|
+
end
|
97
|
+
__attribute_list__
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
%w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
|
103
|
+
end
|
104
|
+
|
105
|
+
class Object
|
106
|
+
def attributes *a, &b
|
107
|
+
sc =
|
108
|
+
class << self
|
109
|
+
self
|
110
|
+
end
|
111
|
+
sc.attributes *a, &b
|
112
|
+
end
|
113
|
+
%w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
|
114
|
+
end
|
115
|
+
|
116
|
+
class Module
|
117
|
+
include Attributes
|
118
|
+
end
|
data/lib/attributes.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Attributes
|
2
|
+
Attributes::VERSION = '5.0.0' unless defined? Attributes::VERSION
|
3
|
+
def self.version() Attributes::VERSION end
|
4
|
+
|
5
|
+
class List < ::Array
|
6
|
+
def << element
|
7
|
+
super
|
8
|
+
self
|
9
|
+
ensure
|
10
|
+
uniq!
|
11
|
+
index!
|
12
|
+
end
|
13
|
+
def index!
|
14
|
+
@index ||= Hash.new
|
15
|
+
each{|element| @index[element] = true}
|
16
|
+
end
|
17
|
+
def include? element
|
18
|
+
@index ||= Hash.new
|
19
|
+
@index[element] ? true : false
|
20
|
+
end
|
21
|
+
def initializers
|
22
|
+
@initializers ||= Hash.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def attributes *a, &b
|
27
|
+
unless a.empty?
|
28
|
+
returned = Hash.new
|
29
|
+
|
30
|
+
hashes, names = a.partition{|x| Hash === x}
|
31
|
+
names_and_defaults = {}
|
32
|
+
hashes.each{|h| names_and_defaults.update h}
|
33
|
+
names.flatten.compact.each{|name| names_and_defaults.update name => nil}
|
34
|
+
|
35
|
+
initializers = __attributes__.initializers
|
36
|
+
|
37
|
+
names_and_defaults.each do |name, default|
|
38
|
+
raise NameError, "bad instance variable name '@#{ name }'" if "@#{ name }" =~ %r/[!?=]$/o
|
39
|
+
name = name.to_s
|
40
|
+
|
41
|
+
initialize = b || lambda { default }
|
42
|
+
initializer = lambda do |this|
|
43
|
+
Object.instance_method('instance_eval').bind(this).call &initialize
|
44
|
+
end
|
45
|
+
initializer_id = initializer.object_id
|
46
|
+
__attributes__.initializers[name] = initializer
|
47
|
+
|
48
|
+
module_eval <<-code
|
49
|
+
def #{ name }=(*value, &block)
|
50
|
+
value.unshift block if block
|
51
|
+
@#{ name } = value.first
|
52
|
+
end
|
53
|
+
code
|
54
|
+
|
55
|
+
module_eval <<-code
|
56
|
+
def #{ name }(*value, &block)
|
57
|
+
value.unshift block if block
|
58
|
+
return self.send('#{ name }=', value.first) unless value.empty?
|
59
|
+
#{ name }! unless defined? @#{ name }
|
60
|
+
@#{ name }
|
61
|
+
end
|
62
|
+
code
|
63
|
+
|
64
|
+
module_eval <<-code
|
65
|
+
def #{ name }!
|
66
|
+
initializer = ObjectSpace._id2ref #{ initializer_id }
|
67
|
+
self.#{ name } = initializer.call(self)
|
68
|
+
@#{ name }
|
69
|
+
end
|
70
|
+
code
|
71
|
+
|
72
|
+
module_eval <<-code
|
73
|
+
def #{ name }?
|
74
|
+
#{ name }
|
75
|
+
end
|
76
|
+
code
|
77
|
+
|
78
|
+
attributes << name
|
79
|
+
returned[name] = initializer
|
80
|
+
end
|
81
|
+
|
82
|
+
returned
|
83
|
+
else
|
84
|
+
begin
|
85
|
+
__attribute_list__
|
86
|
+
rescue NameError
|
87
|
+
singleton_class =
|
88
|
+
class << self
|
89
|
+
self
|
90
|
+
end
|
91
|
+
klass = self
|
92
|
+
singleton_class.module_eval do
|
93
|
+
attribute_list = List.new
|
94
|
+
define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
|
95
|
+
alias_method '__attribute_list__', 'attribute_list'
|
96
|
+
end
|
97
|
+
__attribute_list__
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
%w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
|
103
|
+
end
|
104
|
+
|
105
|
+
class Object
|
106
|
+
def attributes *a, &b
|
107
|
+
sc =
|
108
|
+
class << self
|
109
|
+
self
|
110
|
+
end
|
111
|
+
sc.attributes *a, &b
|
112
|
+
end
|
113
|
+
%w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
|
114
|
+
end
|
115
|
+
|
116
|
+
class Module
|
117
|
+
include Attributes
|
118
|
+
end
|
data/samples/a.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# basic usage is like attr, but note that attribute defines a suite of methods
|
3
|
+
#
|
4
|
+
require 'attributes'
|
5
|
+
|
6
|
+
class C
|
7
|
+
attribute 'a'
|
8
|
+
end
|
9
|
+
|
10
|
+
c = C.new
|
11
|
+
|
12
|
+
c.a = 42
|
13
|
+
p c.a #=> 42
|
14
|
+
p 'forty-two' if c.a? #=> 'forty-two'
|
15
|
+
|
16
|
+
#
|
17
|
+
# attributes works on object too
|
18
|
+
#
|
19
|
+
o = Object.new
|
20
|
+
o.attribute 'answer' => 42
|
21
|
+
p o.answer #=> 42
|
data/samples/b.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#
|
2
|
+
# default values may be given either directly or as a block which will be
|
3
|
+
# evaluated in the context of self. in both cases (value or block) the
|
4
|
+
# default is set only once and only if needed - it's a lazy evaluation. the
|
5
|
+
# 'banger' method can be used to re-initialize a variable at any point whether
|
6
|
+
# or not it's already been initialized.
|
7
|
+
#
|
8
|
+
require 'attributes'
|
9
|
+
|
10
|
+
class C
|
11
|
+
attribute :a => 42
|
12
|
+
attribute(:b){ Float a }
|
13
|
+
end
|
14
|
+
|
15
|
+
c = C.new
|
16
|
+
p c.a #=> 42
|
17
|
+
p c.b #=> 42.0
|
18
|
+
|
19
|
+
c.a = 43
|
20
|
+
p c.a #=> 43
|
21
|
+
c.a!
|
22
|
+
p c.a #=> 42
|
data/samples/c.rb
ADDED
data/samples/d.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# a nice feature is that all attributes are enumerated in the class. this,
|
3
|
+
# combined with the fact that the getter method is defined so as to delegate
|
4
|
+
# to the setter when an argument is given, means bulk initialization and/or
|
5
|
+
# attribute traversal is very easy.
|
6
|
+
#
|
7
|
+
require 'attributes'
|
8
|
+
|
9
|
+
class C
|
10
|
+
attributes %w( x y z )
|
11
|
+
|
12
|
+
def attributes
|
13
|
+
self.class.attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
attributes.each_with_index{|a,i| send a, i}
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
attributes.inject({}){|h,a| h.update a => send(a)}
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
to_hash.inspect
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
c = C.new
|
30
|
+
p c.attributes
|
31
|
+
p c
|
32
|
+
|
33
|
+
c.x 'forty-two'
|
34
|
+
p c.x
|
data/samples/e.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#
|
2
|
+
# my favourite element of attributes is that getters can also be setters.
|
3
|
+
# this allows incredibly clean looking code like
|
4
|
+
#
|
5
|
+
require 'attributes'
|
6
|
+
|
7
|
+
class Config
|
8
|
+
attributes %w( host port)
|
9
|
+
def initialize(&block) instance_eval &block end
|
10
|
+
end
|
11
|
+
|
12
|
+
conf = Config.new{
|
13
|
+
host 'codeforpeople.org'
|
14
|
+
|
15
|
+
port 80
|
16
|
+
}
|
17
|
+
|
18
|
+
p conf
|
data/samples/f.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# of course attributes works as well at class/module level as at instance
|
3
|
+
# level
|
4
|
+
#
|
5
|
+
require 'attributes'
|
6
|
+
|
7
|
+
module Logging
|
8
|
+
Level_names = {
|
9
|
+
0 => 'INFO',
|
10
|
+
# ...
|
11
|
+
42 => 'DEBUG',
|
12
|
+
}
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attribute 'level' => 42
|
16
|
+
attribute('level_name'){ Level_names[level] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
p Logging.level
|
21
|
+
p Logging.level_name
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attributes1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 5.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mitesh Jain
|
9
|
+
autorequire: attributes
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-24 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email: mitijain123@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- a.rb
|
21
|
+
- b.rb
|
22
|
+
- gemspec.rb
|
23
|
+
- gen_readme.rb
|
24
|
+
- install.rb
|
25
|
+
- lib/attributes-5.0.0.rb
|
26
|
+
- lib/attributes.rb
|
27
|
+
- README
|
28
|
+
- README.tmpl
|
29
|
+
- samples/a.rb
|
30
|
+
- samples/b.rb
|
31
|
+
- samples/c.rb
|
32
|
+
- samples/d.rb
|
33
|
+
- samples/e.rb
|
34
|
+
- samples/f.rb
|
35
|
+
homepage:
|
36
|
+
licenses: []
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.8.10
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: attributes
|
59
|
+
test_files: []
|