og 0.7.0 → 0.8.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.
- data/AUTHORS +14 -4
- data/ChangeLog +192 -1
- data/README.og +2 -1
- data/RELEASES.og +35 -0
- data/Rakefile +1 -1
- data/examples/og/mock_example.rb +6 -9
- data/examples/og/mysql_to_psql.rb +100 -0
- data/examples/og/run.rb +8 -17
- data/lib/glue/array.rb +1 -1
- data/lib/glue/attribute.rb +86 -0
- data/lib/glue/cache.rb +1 -1
- data/lib/glue/hash.rb +1 -1
- data/lib/glue/inflector.rb +1 -1
- data/lib/glue/logger.rb +118 -18
- data/lib/glue/mixins.rb +1 -1
- data/lib/glue/number.rb +1 -1
- data/lib/glue/pool.rb +1 -1
- data/lib/glue/property.rb +48 -31
- data/lib/glue/string.rb +1 -1
- data/lib/glue/time.rb +2 -2
- data/lib/glue/validation.rb +400 -0
- data/lib/glue.rb +7 -8
- data/lib/og/backend.rb +47 -46
- data/lib/og/backends/mysql.rb +64 -63
- data/lib/og/backends/psql.rb +73 -72
- data/lib/og/connection.rb +7 -8
- data/lib/og/enchant.rb +80 -0
- data/lib/og/meta.rb +21 -21
- data/lib/og/mock.rb +31 -88
- data/lib/og/version.rb +6 -5
- data/lib/og.rb +95 -129
- data/test/tc_og.rb +3 -3
- data/vendor/extensions/_base.rb +153 -0
- data/vendor/extensions/_template.rb +36 -0
- data/vendor/extensions/all.rb +21 -0
- data/vendor/extensions/array.rb +68 -0
- data/vendor/extensions/binding.rb +224 -0
- data/vendor/extensions/class.rb +50 -0
- data/vendor/extensions/continuation.rb +71 -0
- data/vendor/extensions/enumerable.rb +250 -0
- data/vendor/extensions/hash.rb +23 -0
- data/vendor/extensions/io.rb +58 -0
- data/vendor/extensions/kernel.rb +42 -0
- data/vendor/extensions/module.rb +114 -0
- data/vendor/extensions/numeric.rb +230 -0
- data/vendor/extensions/object.rb +164 -0
- data/vendor/extensions/ostruct.rb +41 -0
- data/vendor/extensions/string.rb +316 -0
- data/vendor/extensions/symbol.rb +28 -0
- metadata +24 -4
- data/lib/glue/property.rb.old +0 -307
@@ -0,0 +1,316 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
#
|
4
|
+
# == extensions/string.rb
|
5
|
+
#
|
6
|
+
# Adds methods to the builtin String class.
|
7
|
+
#
|
8
|
+
|
9
|
+
require "extensions/_base"
|
10
|
+
|
11
|
+
|
12
|
+
ExtensionsProject.implement(String, :leftmost_indent) do
|
13
|
+
class String
|
14
|
+
#
|
15
|
+
# Returns the size of the smallest indent of any line in the string.
|
16
|
+
# Emits a warning if tabs are found, and if <tt>$VERBOSE</tt> is on.
|
17
|
+
# You can use #expand_tabs to avoid this. This method is primarily intended
|
18
|
+
# for use by #tabto and is not likely to be all that useful in its own
|
19
|
+
# right.
|
20
|
+
#
|
21
|
+
def leftmost_indent
|
22
|
+
tabs_found = false
|
23
|
+
scan(/^([ \t]*)\S/).flatten.map { |ws|
|
24
|
+
tabs_found = true if ws =~ /\t/
|
25
|
+
ws.size
|
26
|
+
}.compact.min
|
27
|
+
ensure
|
28
|
+
if tabs_found and $VERBOSE
|
29
|
+
$stderr.puts %{
|
30
|
+
String#leftmost_indent: warning: tabs treated as spaces
|
31
|
+
(value: #{self.inspect[0..30]}...")
|
32
|
+
}.strip
|
33
|
+
end
|
34
|
+
end
|
35
|
+
protected :leftmost_indent
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
ExtensionsProject.implement(String, :expand_tabs) do
|
41
|
+
class String
|
42
|
+
#
|
43
|
+
# Expands tabs to +n+ spaces. Non-destructive. If +n+ is 0, then tabs are
|
44
|
+
# simply removed. Raises an exception if +n+ is negative.
|
45
|
+
#
|
46
|
+
#--
|
47
|
+
# Thanks to GGaramuno for a more efficient algorithm. Very nice.
|
48
|
+
def expand_tabs(n=8)
|
49
|
+
n = n.to_int
|
50
|
+
raise ArgumentError, "n must be >= 0" if n < 0
|
51
|
+
return gsub(/\t/, "") if n == 0
|
52
|
+
return gsub(/\t/, " ") if n == 1
|
53
|
+
str = self.dup
|
54
|
+
while
|
55
|
+
str.gsub!(/^([^\t\n]*)(\t+)/) { |f|
|
56
|
+
val = ( n * $2.size - ($1.size % n) )
|
57
|
+
$1 << (' ' * val)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
str
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
ExtensionsProject.implement(String, :indent) do
|
67
|
+
class String
|
68
|
+
#
|
69
|
+
# Indents the string +n+ spaces.
|
70
|
+
#
|
71
|
+
def indent(n)
|
72
|
+
n = n.to_int
|
73
|
+
return outdent(-n) if n < 0
|
74
|
+
gsub(/^/, " "*n)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
ExtensionsProject.implement(String, :outdent) do
|
81
|
+
class String
|
82
|
+
#
|
83
|
+
# Outdents the string +n+ spaces. Initial tabs will cause problems and
|
84
|
+
# cause a warning to be emitted (if warnings are on). Relative indendation
|
85
|
+
# is always preserved. Once the block hits the beginning of the line,
|
86
|
+
# that's it. In the following example, <tt>.</tt> represents space from the
|
87
|
+
# beginning of the line.
|
88
|
+
#
|
89
|
+
# str = %{
|
90
|
+
# ..One
|
91
|
+
# ....Two
|
92
|
+
# }.outdent(4)
|
93
|
+
#
|
94
|
+
# is
|
95
|
+
#
|
96
|
+
# One
|
97
|
+
# ..Two
|
98
|
+
#
|
99
|
+
def outdent(n)
|
100
|
+
n = n.to_int
|
101
|
+
return indent(-n) if n < 0
|
102
|
+
tabto(leftmost_indent - n)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
ExtensionsProject.implement(String, :tabto) do
|
109
|
+
class String
|
110
|
+
#
|
111
|
+
# Move the string to the <tt>n</tt>th column. Relative indentation is preserved.
|
112
|
+
# Column indices begin at 0, so the result is that the leftmost character of
|
113
|
+
# the string has +n+ spaces before it.
|
114
|
+
#
|
115
|
+
# Examples:
|
116
|
+
# "xyz".tabto(0) # -> "xyz"
|
117
|
+
# "xyz".tabto(1) # -> " xyz"
|
118
|
+
# "xyz".tabto(2) # -> " xyz"
|
119
|
+
# " xyz".tabto(1) # -> " xyz"
|
120
|
+
#
|
121
|
+
# str = <<EOF
|
122
|
+
# Hello, my name
|
123
|
+
# is Gerald.
|
124
|
+
# EOF
|
125
|
+
# str.tabto(5) == <<EOF # -> true
|
126
|
+
# Hello, my name
|
127
|
+
# is Gerald.
|
128
|
+
# EOF
|
129
|
+
#
|
130
|
+
def tabto(n)
|
131
|
+
n = n.to_int
|
132
|
+
n = 0 if n < 0
|
133
|
+
find = " " * leftmost_indent()
|
134
|
+
replace = " " * (n)
|
135
|
+
gsub(/^#{find}/, replace)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
ExtensionsProject.implement(String, :taballto) do
|
142
|
+
class String
|
143
|
+
#
|
144
|
+
# Tabs all lines in the string to column +n+. That is, relative indentation
|
145
|
+
# is _not_ preserved.
|
146
|
+
#
|
147
|
+
def taballto(n)
|
148
|
+
n = n.to_int
|
149
|
+
n = 0 if n < 0
|
150
|
+
gsub(/^[ \t]*/, " "*n)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
ExtensionsProject.implement(String, :trim) do
|
157
|
+
class String
|
158
|
+
#
|
159
|
+
# Trims a string:
|
160
|
+
# - removes one initial blank line
|
161
|
+
# - removes trailing spaces on each line
|
162
|
+
# - if +margin+ is given, removes initial spaces up to and including
|
163
|
+
# the margin on each line, plus one space
|
164
|
+
#
|
165
|
+
# This is designed specifically for working with inline documents.
|
166
|
+
# Here-documents are great, except they tend to go against the indentation
|
167
|
+
# of your code. This method allows a convenient way of using %{}-style
|
168
|
+
# documents. For instance:
|
169
|
+
#
|
170
|
+
# USAGE = %{
|
171
|
+
# | usage: prog [-o dir] -h file...
|
172
|
+
# | where
|
173
|
+
# | -o dir outputs to DIR
|
174
|
+
# | -h prints this message
|
175
|
+
# }.trim("|")
|
176
|
+
#
|
177
|
+
# # USAGE == "usage: prog [-o dir] -h file...\n where"...
|
178
|
+
# # (note single space to right of margin is deleted)
|
179
|
+
#
|
180
|
+
# Note carefully that if no margin string is given, then there is no
|
181
|
+
# clipping at the beginning of each line and your string will remain
|
182
|
+
# indented. You can use <tt>tabto(0)</tt> to align it with the left of
|
183
|
+
# screen (while preserving relative indentation).
|
184
|
+
#
|
185
|
+
# USAGE = %{
|
186
|
+
# usage: prog [-o dir] -h file...
|
187
|
+
# where
|
188
|
+
# -o dir outputs to DIR
|
189
|
+
# -h prints this message
|
190
|
+
# }.trim.tabto(0)
|
191
|
+
#
|
192
|
+
# # USAGE == (same as last example)
|
193
|
+
#
|
194
|
+
def trim(margin=nil)
|
195
|
+
s = self.dup
|
196
|
+
# Remove initial blank line.
|
197
|
+
s.sub!(/\A[ \t]*\n/, "")
|
198
|
+
# Get rid of the margin, if it's specified.
|
199
|
+
unless margin.nil?
|
200
|
+
margin_re = Regexp.escape(margin || "")
|
201
|
+
margin_re = /^[ \t]*#{margin_re} ?/
|
202
|
+
s.gsub!(margin_re, "")
|
203
|
+
end
|
204
|
+
# Remove trailing whitespace on each line
|
205
|
+
s.gsub!(/[ \t]+$/, "")
|
206
|
+
s
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
ExtensionsProject.implement(String, :starts_with?) do
|
213
|
+
class String
|
214
|
+
#
|
215
|
+
# Returns true iff this string starts with +str+.
|
216
|
+
# "Hello, world".starts_with?("He") # -> true
|
217
|
+
# "Hello, world".starts_with?("Green") # -> false
|
218
|
+
#
|
219
|
+
def starts_with?(str)
|
220
|
+
str = str.to_str
|
221
|
+
head = self[0, str.length]
|
222
|
+
head == str
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
ExtensionsProject.implement(String, :ends_with?) do
|
229
|
+
class String
|
230
|
+
#
|
231
|
+
# Returns true iff this string ends with +str+.
|
232
|
+
# "Hello, world".ends_with?(", world") # -> true
|
233
|
+
# "Hello, world".ends_with?("Green") # -> false
|
234
|
+
#
|
235
|
+
def ends_with?(str)
|
236
|
+
str = str.to_str
|
237
|
+
tail = self[-str.length, str.length]
|
238
|
+
tail == str
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
ExtensionsProject.implement(String, :line) do
|
245
|
+
class String
|
246
|
+
#
|
247
|
+
# Returns a line or lines from the string. +args+ can be a single integer,
|
248
|
+
# two integers or a range, as per <tt>Array#slice</tt>. The return value is
|
249
|
+
# a single String (a single line), an array of Strings (multiple lines) or
|
250
|
+
# +nil+ (out of bounds). Note that lines themselves do not contain a
|
251
|
+
# trailing newline character; that is metadata. Indexes out of bounds are
|
252
|
+
# ignored.
|
253
|
+
#
|
254
|
+
# data = " one \n two \n three \n four \n five \n"
|
255
|
+
# data.line(1) # -> " two "
|
256
|
+
# data.line(0,1) # -> [" one "]
|
257
|
+
# data.line(3..9) # -> [" four ", " five "]
|
258
|
+
# data.line(9) # -> nil
|
259
|
+
#
|
260
|
+
def line(*args)
|
261
|
+
self.split(/\n/).slice(*args)
|
262
|
+
rescue TypeError
|
263
|
+
raise TypeError,
|
264
|
+
"String#line(*args): args must be one Integer, two Integers or a Range"
|
265
|
+
rescue ArgumentError
|
266
|
+
raise ArgumentError,
|
267
|
+
"String#line(*args): args must be one Integer, two Integers or a Range"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
ExtensionsProject.implement(String, :cmp) do
|
274
|
+
class String
|
275
|
+
#
|
276
|
+
# Compare this string to +other+, returning the first index at which they
|
277
|
+
# differ, or +nil+ if they are equal.
|
278
|
+
#
|
279
|
+
# "practise".cmp("practice") # -> 6
|
280
|
+
# "noun".cmp("nouns") # -> 5 (and vice versa)
|
281
|
+
# "fly".cmp("fly") # -> nil
|
282
|
+
#
|
283
|
+
def cmp(other)
|
284
|
+
other = other.to_str
|
285
|
+
if self == other
|
286
|
+
return nil
|
287
|
+
else
|
288
|
+
n = [self.size, other.size].min
|
289
|
+
(0..n).each do |i|
|
290
|
+
return i unless self[i] == other[i]
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
ExtensionsProject.implement(String, :join) do
|
299
|
+
class String
|
300
|
+
#
|
301
|
+
# Join all the lines of the string together, and compress spaces. The resulting string
|
302
|
+
# will have no surrounding whitespace.
|
303
|
+
#
|
304
|
+
# text = %{
|
305
|
+
# Once upon a time,
|
306
|
+
# Little Red Riding Hood ...
|
307
|
+
#
|
308
|
+
# }
|
309
|
+
#
|
310
|
+
# text.join # -> "Once upon a time, Little Red Riding Hood ..."
|
311
|
+
#
|
312
|
+
def join
|
313
|
+
gsub(/([ \t]*\n[ \t]*)+/, ' ').strip
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
#
|
3
|
+
# == extensions/symbol.rb
|
4
|
+
#
|
5
|
+
# Adds methods to the builtin Symbol class.
|
6
|
+
#
|
7
|
+
|
8
|
+
require "extensions/_base"
|
9
|
+
|
10
|
+
|
11
|
+
#
|
12
|
+
# * Symbol#to_proc
|
13
|
+
#
|
14
|
+
ExtensionsProject.implement(Symbol, :to_proc) do
|
15
|
+
class Symbol
|
16
|
+
#
|
17
|
+
# Allows a Symbol to be implicitly converted to a Proc.
|
18
|
+
#
|
19
|
+
# This allows such conveniences as:
|
20
|
+
# %{john terry fiona}.map(&:capitalize) # -> %{John Terry Fiona}
|
21
|
+
# sum = numbers.inject(&:+)
|
22
|
+
#
|
23
|
+
def to_proc
|
24
|
+
proc { |obj, *args| obj.send(self, *args) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.4
|
3
3
|
specification_version: 1
|
4
4
|
name: og
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.8.0
|
7
|
+
date: 2005-01-12
|
8
8
|
summary: Og (ObjectGraph)
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- Rakefile
|
35
35
|
- ChangeLog.1
|
36
36
|
- ChangeLog
|
37
|
+
- examples/og/mysql_to_psql.rb
|
37
38
|
- examples/og/run.rb
|
38
39
|
- examples/og/mock_example.rb
|
39
40
|
- examples/og/README
|
@@ -46,13 +47,15 @@ files:
|
|
46
47
|
- lib/glue/number.rb
|
47
48
|
- lib/glue/time.rb
|
48
49
|
- lib/glue/property.rb
|
49
|
-
- lib/glue/property.rb.old
|
50
50
|
- lib/glue/macro.rb
|
51
51
|
- lib/glue/cache.rb
|
52
52
|
- lib/glue/string.rb
|
53
53
|
- lib/glue/array.rb
|
54
|
+
- lib/glue/validation.rb
|
55
|
+
- lib/glue/attribute.rb
|
54
56
|
- lib/og/backends
|
55
57
|
- lib/og/version.rb
|
58
|
+
- lib/og/enchant.rb
|
56
59
|
- lib/og/connection.rb
|
57
60
|
- lib/og/mock.rb
|
58
61
|
- lib/og/meta.rb
|
@@ -62,6 +65,23 @@ files:
|
|
62
65
|
- lib/og.rb
|
63
66
|
- test/tc_og.rb
|
64
67
|
- test/og/tc_lifecycle.rb
|
68
|
+
- vendor/extensions/enumerable.rb
|
69
|
+
- vendor/extensions/all.rb
|
70
|
+
- vendor/extensions/hash.rb
|
71
|
+
- vendor/extensions/continuation.rb
|
72
|
+
- vendor/extensions/module.rb
|
73
|
+
- vendor/extensions/binding.rb
|
74
|
+
- vendor/extensions/ostruct.rb
|
75
|
+
- vendor/extensions/kernel.rb
|
76
|
+
- vendor/extensions/class.rb
|
77
|
+
- vendor/extensions/numeric.rb
|
78
|
+
- vendor/extensions/_base.rb
|
79
|
+
- vendor/extensions/io.rb
|
80
|
+
- vendor/extensions/string.rb
|
81
|
+
- vendor/extensions/object.rb
|
82
|
+
- vendor/extensions/array.rb
|
83
|
+
- vendor/extensions/symbol.rb
|
84
|
+
- vendor/extensions/_template.rb
|
65
85
|
test_files: []
|
66
86
|
rdoc_options:
|
67
87
|
- "--main"
|
data/lib/glue/property.rb.old
DELETED
@@ -1,307 +0,0 @@
|
|
1
|
-
# code:
|
2
|
-
# * George Moschovitis <gm@navel.gr>
|
3
|
-
# design:
|
4
|
-
# * Anastastios Koutoumanos <ak@navel.gr>
|
5
|
-
# * Elias Karakoulakis <ekarak@ktismata.com>
|
6
|
-
#
|
7
|
-
# (c) 2004 Navel, all rights reserved.
|
8
|
-
# $Id: property.rb 185 2004-12-10 13:29:09Z gmosx $
|
9
|
-
|
10
|
-
require "glue/array"
|
11
|
-
require "glue/hash"
|
12
|
-
|
13
|
-
module G
|
14
|
-
|
15
|
-
# = Property
|
16
|
-
#
|
17
|
-
# Ruby attributes are typeless and generally this is good. Some times
|
18
|
-
# we need extra metadata though, for example in relational mapping,
|
19
|
-
# or web form population.
|
20
|
-
#
|
21
|
-
# Only Fixnums, Strings, Floats, Times, Booleans are converted.
|
22
|
-
#
|
23
|
-
# The default = methods do not force the types. A special
|
24
|
-
# __force_set method should be used instead.
|
25
|
-
#
|
26
|
-
#--
|
27
|
-
# TODO:
|
28
|
-
# Inject only the really needd methods into Module.
|
29
|
-
# Perhaps a sync is needed in evals (!!!!)
|
30
|
-
#++
|
31
|
-
#
|
32
|
-
class Property
|
33
|
-
# the symbol of the property
|
34
|
-
attr_accessor :symbol
|
35
|
-
# the string representation of the symbol
|
36
|
-
attr_accessor :name
|
37
|
-
# the class of the property
|
38
|
-
attr_accessor :klass
|
39
|
-
# additional metadata (like sql declaratio, sql index, etc)
|
40
|
-
attr_accessor :meta
|
41
|
-
|
42
|
-
def initialize(symbol, klass, meta = {})
|
43
|
-
@symbol, @klass = symbol, klass
|
44
|
-
@meta = meta
|
45
|
-
@name = @symbol.to_s()
|
46
|
-
end
|
47
|
-
|
48
|
-
def ==(other)
|
49
|
-
return @symbol == other.symbol
|
50
|
-
end
|
51
|
-
|
52
|
-
def to_s
|
53
|
-
return name
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
end # module
|
58
|
-
|
59
|
-
class Module
|
60
|
-
|
61
|
-
# Define a property (== typed attribute)
|
62
|
-
# This works like Ruby's standard attr method, ie creates
|
63
|
-
# only one property.
|
64
|
-
#
|
65
|
-
# Use the prop_reader, prop_writer, prop_accessor methods
|
66
|
-
# for multiple properties.
|
67
|
-
#
|
68
|
-
# Examples:
|
69
|
-
# prop String, :name, :sql => "char(32), :sql_index => "name(32)"
|
70
|
-
# --> creates only writer.
|
71
|
-
# prop Fixnum, :oid, writer = true, :sql => "integer PRIMARY KEY"
|
72
|
-
# --> creates reader and writer.
|
73
|
-
#
|
74
|
-
def prop(*params)
|
75
|
-
meta = {}
|
76
|
-
klass = Object
|
77
|
-
|
78
|
-
for param in params
|
79
|
-
if param.is_a?(Class)
|
80
|
-
klass = param
|
81
|
-
elsif param.is_a?(Symbol)
|
82
|
-
symbol = param
|
83
|
-
elsif param.is_a?(TrueClass) or param.is_a?(TrueClass)
|
84
|
-
writer = param
|
85
|
-
elsif param.is_a?(Hash)
|
86
|
-
# the meta hash.
|
87
|
-
meta = param
|
88
|
-
else
|
89
|
-
raise "Error when defining property!"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
unless self.methods.include?(:__props)
|
94
|
-
eval %{
|
95
|
-
# Properties
|
96
|
-
# An array is used to enforce order.
|
97
|
-
def __props
|
98
|
-
@__props
|
99
|
-
end
|
100
|
-
|
101
|
-
def __props=(props)
|
102
|
-
@__props = props
|
103
|
-
end
|
104
|
-
|
105
|
-
def __meta
|
106
|
-
@__meta
|
107
|
-
end
|
108
|
-
|
109
|
-
def __meta=(meta)
|
110
|
-
@__meta = meta
|
111
|
-
end
|
112
|
-
}
|
113
|
-
end
|
114
|
-
|
115
|
-
@__props = G::SafeArray.new() unless @__props
|
116
|
-
|
117
|
-
property = G::Property.new(symbol, klass, meta)
|
118
|
-
|
119
|
-
reader = meta[:reader] || true
|
120
|
-
writer = writer || meta[:writer] || false
|
121
|
-
|
122
|
-
__add_prop(property, reader, writer)
|
123
|
-
end
|
124
|
-
|
125
|
-
# Helper method. Accepts a collection of symbols and generates
|
126
|
-
# properties. Only generates reader.
|
127
|
-
#
|
128
|
-
# Example:
|
129
|
-
# prop_reader String, :name, :title, :body, :sql => "char(32)"
|
130
|
-
#
|
131
|
-
def prop_reader(*params)
|
132
|
-
meta = {}
|
133
|
-
klass = Object
|
134
|
-
symbols = []
|
135
|
-
|
136
|
-
for param in params
|
137
|
-
if param.is_a?(Class)
|
138
|
-
klass = param
|
139
|
-
elsif param.is_a?(Symbol)
|
140
|
-
symbols << param
|
141
|
-
elsif param.is_a?(Hash)
|
142
|
-
# the meta hash.
|
143
|
-
meta = param
|
144
|
-
else
|
145
|
-
raise "Error when defining property!"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
meta[:reader] = true
|
150
|
-
meta[:writer] = false
|
151
|
-
|
152
|
-
for symbol in symbols
|
153
|
-
prop(klass, symbol, meta)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Helper method. Accepts a collection of symbols and generates
|
158
|
-
# properties. Only generates writer.
|
159
|
-
#
|
160
|
-
# Example:
|
161
|
-
# prop_writer String, :name, :title, :body, :sql => "char(32)"
|
162
|
-
#
|
163
|
-
def prop_writer(*params)
|
164
|
-
meta = {}
|
165
|
-
klass = Object
|
166
|
-
symbols = []
|
167
|
-
|
168
|
-
for param in params
|
169
|
-
if param.is_a?(Class)
|
170
|
-
klass = param
|
171
|
-
elsif param.is_a?(Symbol)
|
172
|
-
symbols << param
|
173
|
-
elsif param.is_a?(Hash)
|
174
|
-
# the meta hash.
|
175
|
-
meta = param
|
176
|
-
else
|
177
|
-
raise "Error when defining property!"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
meta[:reader] = false
|
182
|
-
meta[:writer] = true
|
183
|
-
|
184
|
-
for symbol in symbols
|
185
|
-
prop(klass, symbol, meta)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
# Helper method. Accepts a collection of symbols and generates
|
190
|
-
# properties. Generates reader and writer.
|
191
|
-
#
|
192
|
-
# Example:
|
193
|
-
# prop_accessor String, :name, :title, :body, :sql => "char(32)"
|
194
|
-
#
|
195
|
-
def prop_accessor(*params)
|
196
|
-
meta = {}
|
197
|
-
klass = Object
|
198
|
-
symbols = []
|
199
|
-
|
200
|
-
for param in params
|
201
|
-
if param.is_a?(Class)
|
202
|
-
klass = param
|
203
|
-
elsif param.is_a?(Symbol)
|
204
|
-
symbols << param
|
205
|
-
elsif param.is_a?(Hash)
|
206
|
-
# the meta hash.
|
207
|
-
meta = param
|
208
|
-
else
|
209
|
-
raise "Error when defining property!"
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
meta[:reader] = true
|
214
|
-
meta[:writer] = true
|
215
|
-
|
216
|
-
for symbol in symbols
|
217
|
-
prop(klass, symbol, meta)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Add the property
|
222
|
-
#
|
223
|
-
def __add_prop(prop, reader = true, writer = true)
|
224
|
-
if idx = @__props.index(prop)
|
225
|
-
# override in case of duplicates. Keep the order of the props.
|
226
|
-
@__props[idx] = prop
|
227
|
-
else
|
228
|
-
@__props << prop
|
229
|
-
end
|
230
|
-
|
231
|
-
# Precompile the property read/write methods
|
232
|
-
|
233
|
-
s, klass = prop.symbol, prop.klass
|
234
|
-
|
235
|
-
if reader
|
236
|
-
module_eval %{
|
237
|
-
def #{s}
|
238
|
-
return @#{s}
|
239
|
-
end
|
240
|
-
}
|
241
|
-
end
|
242
|
-
|
243
|
-
# gmosx: __force_xxx reuses xxx= to allow for easier
|
244
|
-
# overrides.
|
245
|
-
if writer
|
246
|
-
module_eval %{
|
247
|
-
def #{s}=(val)
|
248
|
-
@#{s} = val
|
249
|
-
end
|
250
|
-
|
251
|
-
def __force_#{s}(val)
|
252
|
-
self.#{s}=(} + case klass.name
|
253
|
-
when Fixnum.name
|
254
|
-
"val.to_i()"
|
255
|
-
when String.name
|
256
|
-
"val.to_s()"
|
257
|
-
when Float.name
|
258
|
-
"val.to_f()"
|
259
|
-
when Time.name
|
260
|
-
"Time.parse(val.to_s())"
|
261
|
-
when TrueClass.name, FalseClass.name
|
262
|
-
"val.to_i() > 0"
|
263
|
-
else
|
264
|
-
"val"
|
265
|
-
end + %{)
|
266
|
-
end
|
267
|
-
}
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
# Attach metadata
|
272
|
-
#
|
273
|
-
def meta(key, val)
|
274
|
-
@__meta = G::SafeHash.new unless @__meta
|
275
|
-
|
276
|
-
@__meta[key] = [] unless @__meta[key]
|
277
|
-
|
278
|
-
# guard against duplicates, no need to keep order.
|
279
|
-
@__meta[key].delete_if { |v| val == v }
|
280
|
-
@__meta[key] << val
|
281
|
-
end
|
282
|
-
|
283
|
-
# This method is typically called before including other
|
284
|
-
# modules to preserve properties order.
|
285
|
-
#
|
286
|
-
def inherit_meta(mod = superclass)
|
287
|
-
# concat props.
|
288
|
-
if mod.__props
|
289
|
-
@__props = G::SafeArray.new unless @__props
|
290
|
-
|
291
|
-
mod.__props.each { |p|
|
292
|
-
__add_prop(p)
|
293
|
-
}
|
294
|
-
end
|
295
|
-
|
296
|
-
# concat metadata
|
297
|
-
if mod.__meta
|
298
|
-
mod.__meta.each { |k, val|
|
299
|
-
val.each { |v|
|
300
|
-
meta(k, v)
|
301
|
-
} if val
|
302
|
-
}
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
end
|
307
|
-
|