og 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,250 @@
|
|
1
|
+
#
|
2
|
+
# == extensions/enumerable.rb
|
3
|
+
#
|
4
|
+
# Adds methods to the builtin Enumerable module.
|
5
|
+
#
|
6
|
+
|
7
|
+
require "extensions/_base"
|
8
|
+
|
9
|
+
#
|
10
|
+
# * Enumerable#build_hash
|
11
|
+
#
|
12
|
+
ExtensionsProject.implement(Enumerable, :build_hash) do
|
13
|
+
module Enumerable
|
14
|
+
#
|
15
|
+
# Like <tt>#map</tt>/<tt>#collect</tt>, but it generates a Hash. The block
|
16
|
+
# is expected to return two values: the key and the value for the new hash.
|
17
|
+
# numbers = (1..3)
|
18
|
+
# squares = numbers.build_hash { |n| [n, n*n] } # 1=>1, 2=>4, 3=>9
|
19
|
+
# sq_roots = numbers.build_hash { |n| [n*n, n] } # 1=>1, 4=>2, 9=>3
|
20
|
+
#
|
21
|
+
def build_hash
|
22
|
+
result = {}
|
23
|
+
self.each do |elt|
|
24
|
+
key, value = yield elt
|
25
|
+
result[key] = value
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# There was a bug in Hash which causes the above code to issue a warning when
|
32
|
+
# used with a Hash. That was fixed on 2003-10-24.
|
33
|
+
if RUBY_RELEASE_DATE < "2003-10-25"
|
34
|
+
class Hash #:nodoc:
|
35
|
+
def build_hash
|
36
|
+
result = {}
|
37
|
+
self.each_pair do |k, v|
|
38
|
+
key, value = yield(k, v)
|
39
|
+
result[key] = value
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
#
|
49
|
+
# Enumerable#mapf
|
50
|
+
#
|
51
|
+
ExtensionsProject.implement(Enumerable, :mapf) do
|
52
|
+
module Enumerable
|
53
|
+
#
|
54
|
+
# "map function"
|
55
|
+
# enum.mapf(:x)
|
56
|
+
# is short for
|
57
|
+
# enum.map { |elt| elt.x }
|
58
|
+
#
|
59
|
+
def mapf(message)
|
60
|
+
self.map { |elt| elt.send(message) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
#
|
67
|
+
# Enumerable#collectf
|
68
|
+
#
|
69
|
+
ExtensionsProject.implement(Enumerable, :collectf) do
|
70
|
+
module Enumerable
|
71
|
+
alias collectf mapf
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
#
|
77
|
+
# * Enumerable#includes?
|
78
|
+
#
|
79
|
+
ExtensionsProject.implement(Enumerable, :includes?) do
|
80
|
+
module Enumerable
|
81
|
+
alias includes? include?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
#
|
87
|
+
# * Enumerable#contains?
|
88
|
+
#
|
89
|
+
ExtensionsProject.implement(Enumerable, :contains?) do
|
90
|
+
module Enumerable
|
91
|
+
alias contains? include?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
#
|
97
|
+
# * Enumerable#has?
|
98
|
+
#
|
99
|
+
ExtensionsProject.implement(Enumerable, :has?) do
|
100
|
+
module Enumerable
|
101
|
+
alias has? include?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
#
|
107
|
+
# * Enumerable#map_with_index
|
108
|
+
#
|
109
|
+
ExtensionsProject.implement(Enumerable, :map_with_index) do
|
110
|
+
module Enumerable
|
111
|
+
#
|
112
|
+
# Same as Enumerable#map, but the index is yielded as well. See
|
113
|
+
# Enumerable#each_with_index.
|
114
|
+
# puts files.map_with_index { |fn, idx| "#{idx}. #{fn}" }
|
115
|
+
# print "Please select a file (0-#{files.size}): "
|
116
|
+
#
|
117
|
+
def map_with_index
|
118
|
+
result = []
|
119
|
+
self.each_with_index do |elt, idx|
|
120
|
+
result << yield(elt, idx)
|
121
|
+
end
|
122
|
+
result
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
#
|
129
|
+
# * Enumerable#collect_with_index
|
130
|
+
#
|
131
|
+
ExtensionsProject.implement(Enumerable, :collect_with_index) do
|
132
|
+
module Enumerable
|
133
|
+
alias collect_with_index map_with_index
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
#
|
139
|
+
# * Enumerable#partition_by
|
140
|
+
#
|
141
|
+
ExtensionsProject.implement(Enumerable, :partition_by) do
|
142
|
+
module Enumerable
|
143
|
+
#
|
144
|
+
# See Enumerable#partition for the background. #partition_by is best
|
145
|
+
# explained by example.
|
146
|
+
#
|
147
|
+
# (1..5).partition_by { |n| n % 3 }
|
148
|
+
# # -> { 0 => [3], 1 => [1, 4], 2 => [2,5] }
|
149
|
+
#
|
150
|
+
# ["I had", 1, "dollar and", 50, "cents"].partition_by { |e| e.class }
|
151
|
+
# # -> { String => ["I had","dollar and","cents"], Fixnum => [1,50] }
|
152
|
+
#
|
153
|
+
# #partition_by is used to group items in a collection by something they
|
154
|
+
# have in common. The common factor is the key in the resulting hash, the
|
155
|
+
# array of like elements is the value.
|
156
|
+
#
|
157
|
+
def partition_by
|
158
|
+
result = {}
|
159
|
+
self.each do |e|
|
160
|
+
value = yield e
|
161
|
+
(result[value] ||= []) << e
|
162
|
+
end
|
163
|
+
result
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
#
|
170
|
+
# * Enumerable#none?
|
171
|
+
#
|
172
|
+
ExtensionsProject.implement(Enumerable, :none?) do
|
173
|
+
module Enumerable
|
174
|
+
#
|
175
|
+
# Enumerable#none? is the logical opposite of the builtin method Enumerable#any?. It
|
176
|
+
# returns +true+ if and only if _none_ of the elements in the collection satisfy the
|
177
|
+
# predicate.
|
178
|
+
#
|
179
|
+
# If no predicate is provided, Enumerable#none? returns +true+ if and only if _none_ of the
|
180
|
+
# elements have a true value (i.e. not +nil+ or +false+).
|
181
|
+
#
|
182
|
+
# [].none? # true
|
183
|
+
# [nil].none? # true
|
184
|
+
# [5,8,9].none? # false
|
185
|
+
# (1...10).none? { |n| n < 0 } # true
|
186
|
+
# (1...10).none? { |n| n > 0 } # false
|
187
|
+
#
|
188
|
+
def none? # :yield: e
|
189
|
+
if block_given?
|
190
|
+
not self.any? { |e| yield e }
|
191
|
+
else
|
192
|
+
not self.any?
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
#
|
200
|
+
# * Enumerable#one?
|
201
|
+
#
|
202
|
+
ExtensionsProject.implement(Enumerable, :one?) do
|
203
|
+
module Enumerable
|
204
|
+
#
|
205
|
+
# Enumerable#one? returns +true+ if and only if <em>exactly one</em> element in the
|
206
|
+
# collection satisfies the given predicate.
|
207
|
+
#
|
208
|
+
# If no predicate is provided, Enumerable#one? returns +true+ if and only if <em>exactly
|
209
|
+
# one</em> element has a true value (i.e. not +nil+ or +false+).
|
210
|
+
#
|
211
|
+
# [].one? # false
|
212
|
+
# [nil].one? # false
|
213
|
+
# [5].one? # true
|
214
|
+
# [5,8,9].one? # false
|
215
|
+
# (1...10).one? { |n| n == 5 } # true
|
216
|
+
# (1...10).one? { |n| n < 5 } # false
|
217
|
+
#
|
218
|
+
def one? # :yield: e
|
219
|
+
matches = 0
|
220
|
+
if block_given?
|
221
|
+
self.each do |e|
|
222
|
+
if yield(e)
|
223
|
+
matches += 1
|
224
|
+
return false if matches > 1
|
225
|
+
end
|
226
|
+
end
|
227
|
+
return (matches == 1)
|
228
|
+
else
|
229
|
+
one? { |e| e }
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
#
|
237
|
+
# * Object.in?
|
238
|
+
# This has special treatment: it's included here and in object.rb, so we don't
|
239
|
+
# want a warning if it's alredy defined.
|
240
|
+
#
|
241
|
+
unless Object.method_defined?(:in?)
|
242
|
+
ExtensionsProject.implement(Object, :in?) do
|
243
|
+
class Object
|
244
|
+
def in?(enumerable) # :nodoc: It's documented in object.rb.
|
245
|
+
enumerable.include?(self)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
#
|
3
|
+
# == extensions/hash.rb
|
4
|
+
#
|
5
|
+
# Adds methods to the builtin Hash class.
|
6
|
+
#
|
7
|
+
|
8
|
+
require "extensions/_base"
|
9
|
+
|
10
|
+
#
|
11
|
+
# * Hash#select!
|
12
|
+
#
|
13
|
+
ExtensionsProject.implement(Hash, :select!) do
|
14
|
+
class Hash
|
15
|
+
#
|
16
|
+
# In-place version of Hash#select. (Counterpart to, and opposite of, the
|
17
|
+
# built-in #reject!)
|
18
|
+
#
|
19
|
+
def select!
|
20
|
+
reject! { |k,v| not yield(k,v) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
#
|
4
|
+
# == extensions/io.rb
|
5
|
+
#
|
6
|
+
# Adds methods to the builtin IO class.
|
7
|
+
#
|
8
|
+
|
9
|
+
require "extensions/_base"
|
10
|
+
|
11
|
+
# This is Ruby's built-in IO class.
|
12
|
+
class IO
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# * IO.write
|
17
|
+
#
|
18
|
+
ExtensionsProject.implement(IO, :write, :class) do
|
19
|
+
class << IO
|
20
|
+
#
|
21
|
+
# Writes the given data to the given path and closes the file. This is
|
22
|
+
# done in binary mode, complementing <tt>IO.read</tt> in standard Ruby.
|
23
|
+
#
|
24
|
+
# Returns the number of bytes written.
|
25
|
+
#
|
26
|
+
def write(path, data)
|
27
|
+
File.open(path, "wb") do |file|
|
28
|
+
return file.write(data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# * IO.writelines
|
36
|
+
#
|
37
|
+
ExtensionsProject.implement(IO, :writelines, :class) do
|
38
|
+
class << IO
|
39
|
+
#
|
40
|
+
# Writes the given array of data to the given path and closes the file.
|
41
|
+
# This is done in binary mode, complementing <tt>IO.readlines</tt> in
|
42
|
+
# standard Ruby.
|
43
|
+
#
|
44
|
+
# Note that +readlines+ (the standard Ruby method) returns an array of lines
|
45
|
+
# <em>with newlines intact</em>, whereas +writelines+ uses +puts+, and so
|
46
|
+
# appends newlines if necessary. In this small way, +readlines+ and
|
47
|
+
# +writelines+ are not exact opposites.
|
48
|
+
#
|
49
|
+
# Returns +nil+.
|
50
|
+
#
|
51
|
+
def writelines(path, data)
|
52
|
+
File.open(path, "wb") do |file|
|
53
|
+
file.puts(data)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
#
|
3
|
+
# == extensions/module.rb
|
4
|
+
#
|
5
|
+
# Adds methods to the builtin Kernel module.
|
6
|
+
#
|
7
|
+
|
8
|
+
require "extensions/_base"
|
9
|
+
|
10
|
+
ExtensionsProject.implement(Kernel, :require_relative) do
|
11
|
+
module Kernel
|
12
|
+
#
|
13
|
+
# <tt>require_relative</tt> complements the builtin method <tt>require</tt> by allowing
|
14
|
+
# you to load a file that is <em>relative to the file containing the require_relative
|
15
|
+
# statement</em>.
|
16
|
+
#
|
17
|
+
# When you use <tt>require</tt> to load a file, you are usually accessing functionality
|
18
|
+
# that has been properly installed, and made accessible, in your system. <tt>require</tt>
|
19
|
+
# does not offer a good solution for loading files within the project's code. This may
|
20
|
+
# be useful during a development phase, for accessing test data, or even for accessing
|
21
|
+
# files that are "locked" away inside a project, not intended for outside use.
|
22
|
+
#
|
23
|
+
# For example, if you have unit test classes in the "test" directory, and data for them
|
24
|
+
# under the test "test/data" directory, then you might use a line like this in a test
|
25
|
+
# case:
|
26
|
+
#
|
27
|
+
# require_relative "data/customer_data_1"
|
28
|
+
#
|
29
|
+
# Since neither "test" nor "test/data" are likely to be in Ruby's library path (and for
|
30
|
+
# good reason), a normal <tt>require</tt> won't find them. <tt>require_relative</tt> is
|
31
|
+
# a good solution for this particular problem.
|
32
|
+
#
|
33
|
+
# You may include or omit the extension (<tt>.rb</tt> or <tt>.so</tt>) of the file you
|
34
|
+
# are loading.
|
35
|
+
#
|
36
|
+
# _path_ must respond to <tt>to_str</tt>.
|
37
|
+
#
|
38
|
+
def require_relative(path)
|
39
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
#
|
3
|
+
# == extensions/module.rb
|
4
|
+
#
|
5
|
+
# Adds methods to the builtin Module class.
|
6
|
+
#
|
7
|
+
|
8
|
+
require "extensions/_base"
|
9
|
+
|
10
|
+
ExtensionsProject.implement(Module, :deep_const_get) do
|
11
|
+
class Module
|
12
|
+
#
|
13
|
+
# Recursively dereferences constants separated by "<tt>::</tt>".
|
14
|
+
#
|
15
|
+
# _const_ is a Symbol or responds to #to_str, for compatibility with the builtin method
|
16
|
+
# <tt>Module#const_get</tt>.
|
17
|
+
#
|
18
|
+
# Object.const_get("String") # -> String
|
19
|
+
# Object.const_get(:String) # -> String
|
20
|
+
#
|
21
|
+
# Object.deep_const_get("String") # -> String
|
22
|
+
# Object.deep_const_get(:String) # -> String
|
23
|
+
#
|
24
|
+
# Object.deep_const_get("Process::Sys") # -> Process::Sys
|
25
|
+
# Object.deep_const_get("Regexp::IGNORECASE") # -> 1
|
26
|
+
# Object.deep_const_get("Regexp::MULTILINE") # -> 4
|
27
|
+
#
|
28
|
+
# require 'test/unit'
|
29
|
+
# Test.deep_const_get("Unit::Assertions") # -> Test::Unit::Assertions
|
30
|
+
# Test.deep_const_get("::Test::Unit") # -> Test::Unit
|
31
|
+
#
|
32
|
+
# For resolving classes or modules based on their name, see Module.by_name, which uses this
|
33
|
+
# method.
|
34
|
+
#
|
35
|
+
def deep_const_get(const)
|
36
|
+
if Symbol === const
|
37
|
+
const = const.to_s
|
38
|
+
else
|
39
|
+
const = const.to_str.dup
|
40
|
+
end
|
41
|
+
if const.sub!(/^::/, '')
|
42
|
+
base = Object
|
43
|
+
else
|
44
|
+
base = self
|
45
|
+
end
|
46
|
+
const.split(/::/).inject(base) { |mod, name| mod.const_get(name) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
ExtensionsProject.implement(Module, :by_name, :class) do
|
53
|
+
class Module
|
54
|
+
#
|
55
|
+
# <em>Note: the following documentation uses "class" because it's more common, but it
|
56
|
+
# applies to modules as well.</em>
|
57
|
+
#
|
58
|
+
# Given the _name_ of a class, returns the class itself (i.e. instance of Class). The
|
59
|
+
# dereferencing starts at Object. That is,
|
60
|
+
#
|
61
|
+
# Class.by_name("String")
|
62
|
+
#
|
63
|
+
# is equivalent to
|
64
|
+
#
|
65
|
+
# Object.get_const("String")
|
66
|
+
#
|
67
|
+
# The parameter _name_ is expected to be a Symbol or String, or at least to respond to
|
68
|
+
# <tt>to_str</tt>.
|
69
|
+
#
|
70
|
+
# An ArgumentError is raised if _name_ does not correspond to an existing class. If _name_
|
71
|
+
# is not even a valid class name, the error you'll get is not defined.
|
72
|
+
#
|
73
|
+
# Examples:
|
74
|
+
#
|
75
|
+
# Class.by_name("String") # -> String
|
76
|
+
# Class.by_name("::String") # -> String
|
77
|
+
# Class.by_name("Process::Sys") # -> Process::Sys
|
78
|
+
# Class.by_name("GorillaZ") # -> (ArgumentError)
|
79
|
+
#
|
80
|
+
# Class.by_name("Enumerable") # -> Enumerable
|
81
|
+
# Module.by_name("Enumerable") # -> Enumerable
|
82
|
+
#
|
83
|
+
def Module.by_name(name)
|
84
|
+
if Symbol === name
|
85
|
+
name = name.to_s
|
86
|
+
else
|
87
|
+
name = name.to_str
|
88
|
+
end
|
89
|
+
result = Object.deep_const_get(name)
|
90
|
+
if result.is_a? Module
|
91
|
+
return result
|
92
|
+
else
|
93
|
+
raise ArgumentError, "#{name} is not a class or module"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
ExtensionsProject.implement(Module, :basename) do
|
101
|
+
class Module
|
102
|
+
#
|
103
|
+
# Returns the immediate name of the class/module, stripped of any containing classes or
|
104
|
+
# modules. Compare Ruby's builtin methods <tt>Module#name</tt> and <tt>File.basename</tt>.
|
105
|
+
#
|
106
|
+
# Process::Sys.name # -> "Process::Sys"
|
107
|
+
# Process::Sys.basename # -> "Sys"
|
108
|
+
# String.basename # -> "String"
|
109
|
+
#
|
110
|
+
def basename
|
111
|
+
self.name.sub(/^.*::/, '')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|