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.
Files changed (51) hide show
  1. data/AUTHORS +14 -4
  2. data/ChangeLog +192 -1
  3. data/README.og +2 -1
  4. data/RELEASES.og +35 -0
  5. data/Rakefile +1 -1
  6. data/examples/og/mock_example.rb +6 -9
  7. data/examples/og/mysql_to_psql.rb +100 -0
  8. data/examples/og/run.rb +8 -17
  9. data/lib/glue/array.rb +1 -1
  10. data/lib/glue/attribute.rb +86 -0
  11. data/lib/glue/cache.rb +1 -1
  12. data/lib/glue/hash.rb +1 -1
  13. data/lib/glue/inflector.rb +1 -1
  14. data/lib/glue/logger.rb +118 -18
  15. data/lib/glue/mixins.rb +1 -1
  16. data/lib/glue/number.rb +1 -1
  17. data/lib/glue/pool.rb +1 -1
  18. data/lib/glue/property.rb +48 -31
  19. data/lib/glue/string.rb +1 -1
  20. data/lib/glue/time.rb +2 -2
  21. data/lib/glue/validation.rb +400 -0
  22. data/lib/glue.rb +7 -8
  23. data/lib/og/backend.rb +47 -46
  24. data/lib/og/backends/mysql.rb +64 -63
  25. data/lib/og/backends/psql.rb +73 -72
  26. data/lib/og/connection.rb +7 -8
  27. data/lib/og/enchant.rb +80 -0
  28. data/lib/og/meta.rb +21 -21
  29. data/lib/og/mock.rb +31 -88
  30. data/lib/og/version.rb +6 -5
  31. data/lib/og.rb +95 -129
  32. data/test/tc_og.rb +3 -3
  33. data/vendor/extensions/_base.rb +153 -0
  34. data/vendor/extensions/_template.rb +36 -0
  35. data/vendor/extensions/all.rb +21 -0
  36. data/vendor/extensions/array.rb +68 -0
  37. data/vendor/extensions/binding.rb +224 -0
  38. data/vendor/extensions/class.rb +50 -0
  39. data/vendor/extensions/continuation.rb +71 -0
  40. data/vendor/extensions/enumerable.rb +250 -0
  41. data/vendor/extensions/hash.rb +23 -0
  42. data/vendor/extensions/io.rb +58 -0
  43. data/vendor/extensions/kernel.rb +42 -0
  44. data/vendor/extensions/module.rb +114 -0
  45. data/vendor/extensions/numeric.rb +230 -0
  46. data/vendor/extensions/object.rb +164 -0
  47. data/vendor/extensions/ostruct.rb +41 -0
  48. data/vendor/extensions/string.rb +316 -0
  49. data/vendor/extensions/symbol.rb +28 -0
  50. metadata +24 -4
  51. data/lib/glue/property.rb.old +0 -307
@@ -0,0 +1,153 @@
1
+
2
+ #
3
+ # This file is 'required' by all files that implement standard class
4
+ # extensions as part of the "Ruby/Extensions" project.
5
+ #
6
+ # The "Extensions" project requires 1.8.0 or greater to run, as it is too
7
+ # much hassle at the moment to consider supporting older versions. That may
8
+ # one day be implemented if demand is there. One option would be to require
9
+ # "shim", so that we can assume all 1.8 library methods are implemented.
10
+ #
11
+ # This file is only of interest to developers of the package, so no detailed
12
+ # documentation is included here. However, by way of introduction, this is what
13
+ # it's all about. Each method that is implemented as part of this package is
14
+ # done so through a framework implemented in this file. Take the following
15
+ # simple example:
16
+ #
17
+ # ExtensionsProject.implement(Integer, :even?, :instance) do
18
+ # class Integer
19
+ # #
20
+ # # RDoc comments.
21
+ # #
22
+ # def even?
23
+ # self % 2 == 0
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # This purposes of this are as follows:
29
+ # - if the intended method (in this case IO.write) is already defined,
30
+ # we don't want to overwrite it (we issue a warning and move on)
31
+ # - if the intended method is _not_ implemented as a result of the block,
32
+ # we have not done as we said, and an error is raised
33
+ # - the ExtensionsProject class gathers information on which methods have
34
+ # been implemented, making for a very handy command-line reference (+rbxtm+)
35
+ #
36
+ # The <tt>ExtensionsProject.implement</tt> method is responsible for ensuring
37
+ # these are so. It gives us documentation, and some assurance that the
38
+ # extensions are doing what we say they are doing.
39
+ #
40
+
41
+ # :enddoc:
42
+
43
+ #
44
+ # For what reason does Ruby define Module#methods, Module#instance_methods,
45
+ # and Module#method_defined?, but not Module#instance_method_defined? ?
46
+ #
47
+ # No matter, extending standard classes is the name of the game here.
48
+ #
49
+ class Module
50
+ if Module.method_defined?(:instance_method_defined?)
51
+ STDERR.puts "Warning: Module#instance_method_defined? already defined; not overwriting"
52
+ else
53
+ def instance_method_defined?(_method)
54
+ instance_methods(true).find { |m| m == _method.to_s }
55
+ end
56
+ end
57
+
58
+ if Module.method_defined?(:module_method_defined?)
59
+ STDERR.puts "Warning: Module#module_method_defined? already defined; not overwriting"
60
+ else
61
+ def module_method_defined?(_method)
62
+ singleton_methods(true).find { |m| m == _method.to_s }
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ class ExtensionsProject
69
+
70
+ class << ExtensionsProject
71
+ @@extension_methods = []
72
+
73
+ #
74
+ # The list of methods implemented in this project.
75
+ #
76
+ def extension_methods
77
+ @@extension_methods
78
+ end
79
+
80
+ #
81
+ # Return the name of the project. To be used in error messages, etc., for
82
+ # consistency.
83
+ #
84
+ def project_name
85
+ "Ruby/Extensions"
86
+ end
87
+
88
+ #
89
+ # Wraps around the implementation of a method, emitting a warning if the
90
+ # method is already defined. Returns true to indicate - false to indicate
91
+ # failure (i.e. method is already defined). Raises an error if the
92
+ # specified method is not actually implemented by the block.
93
+ #
94
+ def implement(_module, _method, _type=:instance)
95
+ raise "Internal error: #{__FILE__}:#{__LINE__}" unless
96
+ _module.is_a? Module and
97
+ _method.is_a? Symbol and
98
+ _type == :instance or _type == :class or _type == :module
99
+
100
+ fullname = _module.to_s + string_rep(_type) + _method.to_s
101
+
102
+ if _defined?(_module, _method, _type)
103
+ STDERR.puts "#{project_name}: #{fullname} is already defined; not overwriting"
104
+ return false
105
+ else
106
+ yield # Perform the block; presumably a method implementation.
107
+ if _method == :initialize and _type == :instance
108
+ # Special case; we can't verify this.
109
+ @@extension_methods<< "#{_module}::new"
110
+ else
111
+ unless _defined?(_module, _method, _type)
112
+ raise "#{project_name}: internal error: was supposed to implement " +
113
+ "#{fullname}, but it didn't!"
114
+ end
115
+ @@extension_methods << fullname
116
+ end
117
+ return true
118
+ end
119
+ end
120
+
121
+
122
+ # See whether the given module implements the given method, taking account
123
+ # of the type (class/instance) required.
124
+ def _defined?(_module, _method, _type)
125
+ case _type
126
+ when :instance
127
+ _module.instance_method_defined?(_method) # See definition above.
128
+ when :class, :module
129
+ _module.module_method_defined?(_method) # See definition above.
130
+ end
131
+ end
132
+ private :_defined?
133
+
134
+
135
+ # Return the string representation of the given method type.
136
+ def string_rep(method_type)
137
+ case method_type
138
+ when :instance then "#"
139
+ when :class then "."
140
+ when :module then "."
141
+ else
142
+ nil
143
+ end
144
+ end
145
+ private :string_rep
146
+ end
147
+ end # class ExtensionsProject
148
+
149
+
150
+ if VERSION < "1.8.0"
151
+ raise "#{ExtensionsProject.project_name} requires Ruby 1.8.0 at least (for now)"
152
+ end
153
+
@@ -0,0 +1,36 @@
1
+ #!/usr/local/bin/ruby -w
2
+ # A template for new files in the project; of no interest to end users. An
3
+ # error will be raised if you +require+ it.
4
+ #--
5
+ # :enddoc:
6
+ #
7
+ # == extensions/XXX.rb
8
+ #
9
+ # Adds methods to the builtin XXX class.
10
+ #
11
+
12
+ raise "Do not load this file!"
13
+
14
+ require "extensions/_base"
15
+
16
+ #
17
+ # * Enumerable#build_hash
18
+ #
19
+ ExtensionsProject.implement(Enumerable, :build_hash) do
20
+ module Enumerable
21
+ #
22
+ # Like #map/#collect, but it generates a Hash.
23
+ #
24
+ # [1,5,11].build_hash { |x| [x, x**2] }
25
+ # => { 1 => 2, 5 => 25, 11 => 121 }
26
+ #
27
+ def build_hash
28
+ result = {}
29
+ self.each do |elt|
30
+ key, value = yield elt
31
+ result[key] = value
32
+ end
33
+ result
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # == extensions/all.rb
3
+ #
4
+ # Require this file in order to access all of the standard class extensions
5
+ # available, or require individual extension files to narrow the selection.
6
+ #
7
+
8
+ require 'extensions/array.rb'
9
+ require 'extensions/binding.rb'
10
+ require 'extensions/class.rb'
11
+ require 'extensions/continuation.rb'
12
+ require 'extensions/enumerable.rb'
13
+ require 'extensions/hash.rb'
14
+ require 'extensions/io.rb'
15
+ require 'extensions/kernel.rb'
16
+ require 'extensions/module.rb'
17
+ require 'extensions/numeric.rb'
18
+ require 'extensions/object.rb'
19
+ require 'extensions/ostruct.rb'
20
+ require 'extensions/string.rb'
21
+ require 'extensions/symbol.rb'
@@ -0,0 +1,68 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/array.rb
4
+ #
5
+ # Adds methods to the builtin Array class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ #
11
+ # * Array#select!
12
+ #
13
+ ExtensionsProject.implement(Array, :select!) do
14
+ class Array
15
+ #
16
+ # In-place version of Array#select. (Counterpart to, and opposite of, the
17
+ # built-in #reject!)
18
+ #
19
+ def select!
20
+ reject! { |e| not yield(e) }
21
+ end
22
+ end
23
+ end
24
+
25
+
26
+ #
27
+ # * Array#only
28
+ #
29
+ ExtensionsProject.implement(Array, :only) do
30
+ class Array
31
+ #
32
+ # Returns the _only_ element in the array. Raises an IndexError if the array's size is not
33
+ # 1.
34
+ #
35
+ # [5].only # -> 5
36
+ # [1,2,3].only # -> IndexError
37
+ # [].only # -> IndexError
38
+ #
39
+ def only
40
+ unless size == 1
41
+ raise IndexError, "Array#only called on non-single-element array"
42
+ end
43
+ first
44
+ end
45
+ end
46
+ end
47
+
48
+ #
49
+ # * Array#rand
50
+ #
51
+ ExtensionsProject.implement(Array, :rand) do
52
+ class Array
53
+ #
54
+ # Return a randomly-chosen (using Kernel.rand) element from the array.
55
+ #
56
+ # arr = [48, 71, 3, 39, 15]
57
+ # arr.rand # -> 71
58
+ # arr.rand # -> 39
59
+ # arr.rand # -> 48
60
+ # # etc.
61
+ #
62
+ def rand
63
+ idx = Kernel.rand(size)
64
+ at(idx)
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,224 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/binding.rb
4
+ #
5
+ # Adds methods to the builtin Binding class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+ require "extensions/continuation"
10
+
11
+ #
12
+ # Ruby's built-in Binding class doesn't contain any methods. It is merely a "context" object
13
+ # that can be used in calls to <tt>Kernel.eval</tt>, like this:
14
+ #
15
+ # def example(_binding)
16
+ # return eval("x", _binding)
17
+ # end
18
+ #
19
+ # x = 55
20
+ # current_binding = Kernel.binding
21
+ # example(current_binding) # -> 55
22
+ #
23
+ # The most useful method introduced to Binding by the _extensions_ package is
24
+ # Binding.of_caller. It allows you to access the binding of the calling method, thus
25
+ # enabling you to access local variables in that scope. The other methods are a convenient
26
+ # object-oriented facade for operations that you can already do with #eval as demonstrated
27
+ # above. Here is an example that showcases all of the Binding methods included in
28
+ # _extensions_.
29
+ #
30
+ # def example
31
+ # Binding.of_caller do |b|
32
+ # puts "x + y = #{b.eval('x + y')}"
33
+ # puts "x = #{b[:x]}"
34
+ # puts "Local variables: " + b.local_variables.join(', ')
35
+ # b[:y] += 1
36
+ # puts "Changed value of y in calling context to #{b[:y]}"
37
+ # puts "Is 'z' defined in calling context? " + (b.defined?(:z) ? 'Yes' : 'No')
38
+ # end
39
+ # end
40
+ #
41
+ # x = 5
42
+ # y = 17
43
+ # example
44
+ # y # -> 18
45
+ #
46
+ # Binding.of_caller was written by Florian Gross. The other methods were written by Tom
47
+ # Sawyer.
48
+ #
49
+ class Binding
50
+ end
51
+
52
+ #
53
+ # * Binding.of_caller
54
+ #
55
+ ExtensionsProject.implement(Binding, :of_caller, :class) do
56
+ class Binding
57
+ #
58
+ # This method returns the binding of the method that called your method, enabling you to
59
+ # access its local variables. If you call it without being in a method, it will raise an
60
+ # Exception.
61
+ #
62
+ # === Example
63
+ #
64
+ # def inc_counter
65
+ # Binding.of_caller do |b|
66
+ # eval("counter += 1", b)
67
+ # end
68
+ # # <--- line (A)
69
+ # end
70
+ # counter = 0
71
+ # inc_counter
72
+ # inc_counter
73
+ # counter # -> 2
74
+ #
75
+ # === Warning
76
+ #
77
+ # <tt>Binding.of_caller</tt> must be the _last_ method call in the method. For example,
78
+ # if you insert some code at line *A* in the example above, an Exception will be raised.
79
+ # You'll get away with a simple assignment, but anything involving a method call is
80
+ # trouble.
81
+ #
82
+ # === Explanation
83
+ #
84
+ # It works by installing a temporary trace_func (see Kernel.set_trace_func). This makes
85
+ # available -- to the trace function -- the binding of a method after it has returned.
86
+ # Using a continuation, <tt>Binding.of_caller</tt> will let _your_ method return,
87
+ # retrieve the binding, and return to the <tt>of_caller</tt> call with that binding in
88
+ # hand. This time it executes the block.
89
+ #
90
+ # Because it is actually running <tt>Binding.of_caller</tt> twice, and returning from
91
+ # your method twice, any code between the <tt>of_caller</tt> call and the end of your
92
+ # method will be run twice. This is obviously not desirable, so an Exception is raised
93
+ # if any code is found.
94
+ #
95
+ # See the thread around ruby-talk:109607 for more discussion.
96
+ #
97
+ # === Extra Warning
98
+ #
99
+ # If you have a trace function in place, <tt>Binding.of_caller</tt> will destroy that.
100
+ # Ruby does not allow you to access the current trace function, so it can't be restored
101
+ # afterwards. XXX: will this clash with the profiler and/or debugger?
102
+ #
103
+ # === Credits
104
+ #
105
+ # <tt>Binding.of_caller</tt> was written by Florian Frank.
106
+ #
107
+ def Binding.of_caller(&block)
108
+ old_critical = Thread.critical
109
+ Thread.critical = true
110
+ count = 0
111
+ cc, result, error = Continuation.create(nil, nil)
112
+ error.call if error
113
+
114
+ tracer = lambda do |*args|
115
+ type, context = args[0], args[4]
116
+ if type == "return"
117
+ count += 1
118
+ # First this method and then calling one will return --
119
+ # the trace event of the second event gets the context
120
+ # of the method which called the method that called this
121
+ # method.
122
+ if count == 2
123
+ # It would be nice if we could restore the trace_func
124
+ # that was set before we swapped in our own one, but
125
+ # this is impossible without overloading set_trace_func
126
+ # in current Ruby.
127
+ set_trace_func(nil)
128
+ cc.call(eval("binding", context), nil)
129
+ end
130
+ elsif type != "line"
131
+ set_trace_func(nil)
132
+ error_msg = "Binding.of_caller used in non-method context or " +
133
+ "trailing statements of method using it aren't in the block."
134
+ cc.call(nil, lambda { raise(Exception, error_msg ) })
135
+ end
136
+ end
137
+
138
+ unless result
139
+ set_trace_func(tracer)
140
+ return nil
141
+ else
142
+ Thread.critical = old_critical
143
+ yield result
144
+ end
145
+ end
146
+ end # class Binding
147
+ end
148
+
149
+
150
+ #
151
+ # * Binding#eval
152
+ #
153
+ ExtensionsProject.implement(Binding, :eval, :instance) do
154
+ class Binding
155
+ #
156
+ # Evaluates the given string in the context of this binding.
157
+ #
158
+ def eval(str)
159
+ Kernel.eval(str, self)
160
+ end
161
+ end
162
+ end
163
+
164
+
165
+ #
166
+ # * Binding#local_variables
167
+ #
168
+ ExtensionsProject.implement(Binding, :local_variables, :instance) do
169
+ class Binding
170
+ #
171
+ # Returns the variables that are local to this binding.
172
+ #
173
+ def local_variables
174
+ self.eval('local_variables')
175
+ end
176
+ end
177
+ end
178
+
179
+
180
+ #
181
+ # * Binding#[]
182
+ #
183
+ ExtensionsProject.implement(Binding, :[], :instance) do
184
+ class Binding
185
+ #
186
+ # Returns the value of the given variable in this binding.
187
+ #
188
+ def [](variable)
189
+ self.eval(variable.to_s)
190
+ end
191
+ end
192
+ end
193
+
194
+
195
+ #
196
+ # * Binding#[]=
197
+ #
198
+ ExtensionsProject.implement(Binding, :[]=, :instance) do
199
+ class Binding
200
+ #
201
+ # Sets the given variable (in this binding) to the given value.
202
+ #
203
+ def []=(variable, value)
204
+ self.eval("lambda { |v| #{variable} = v }").call(value)
205
+ end
206
+ end
207
+ end
208
+
209
+
210
+ #
211
+ # * Binding#defined?
212
+ #
213
+ ExtensionsProject.implement(Binding, :defined?, :instance) do
214
+ class Binding
215
+ #
216
+ # Evaluates <tt>defined?</tt> in this binding.
217
+ #
218
+ def defined?(variable)
219
+ self.eval("defined?(#{variable})")
220
+ end
221
+ end
222
+ end
223
+
224
+
@@ -0,0 +1,50 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/class.rb
4
+ #
5
+ # Adds methods to the builtin Class class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ ExtensionsProject.implement(Class, :autoinit) do
11
+ class Class
12
+ #
13
+ # A shorthand for the common chore of assigning initialize's parameters to
14
+ # instance variables. For example:
15
+ #
16
+ # class Circle
17
+ #
18
+ # attr_reader :radius, :location, :area
19
+ #
20
+ # autoinit(:radius, :location) do
21
+ # @area = Math::PI * @radius ** 2
22
+ # end
23
+ #
24
+ # end
25
+ #
26
+ # A TypeError is raised unless all the arguments to +autoinit+ are strings
27
+ # or symbols.
28
+ #
29
+ #--
30
+ # Taken from ruby-talk:11668, by Avi Bryant.
31
+ def autoinit(*args, &block) # :yield:
32
+ unless args.all? { |a| Symbol === a or String === a }
33
+ raise TypeError, "All arguments must be symbols or strings"
34
+ end
35
+ block = proc {} if block.nil?
36
+ define_method(:__init_proc) { block }
37
+ params = args.join(", ")
38
+ vars = args.map { |a| "@#{a}" }.join(", ")
39
+
40
+ code = %{
41
+ def initialize(#{params})
42
+ #{vars} = #{params}
43
+ instance_eval(&__init_proc)
44
+ end
45
+ }
46
+ class_eval code
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,71 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/continuation.rb
4
+ #
5
+ # Adds methods to the builtin Continuation class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+
10
+ #
11
+ # * Continuation.create
12
+ #
13
+ ExtensionsProject.implement(Continuation, :create, :class) do
14
+ class Continuation
15
+ #
16
+ # <tt>Continuation.create</tt> offers a nicer interface for creating continuations than
17
+ # <tt>Kernel.callcc</tt>.
18
+ #
19
+ # === Example
20
+ #
21
+ # Count down from 10 to 0 using a continuation.
22
+ #
23
+ # continuation, counter = Continuation.create(10)
24
+ # puts counter
25
+ # continuation.call(counter - 1) if counter > 0
26
+ #
27
+ # Implement a workalike of <tt>Array#inject</tt> using continuations. For simplicity's
28
+ # sake, this is not fully compatible with the real <tt>#inject</tt>.
29
+ #
30
+ # class Array
31
+ # def cc_inject( value=nil )
32
+ # copy = self.clone
33
+ # cc, result, item = Continuation.create( value, nil )
34
+ # next_item = copy.shift
35
+ # if result and item
36
+ # cc.call( yield(result, item), next_item )
37
+ # elsif next_item
38
+ # cc.call( next_item, result )
39
+ # end
40
+ # result
41
+ # end
42
+ # end
43
+ #
44
+ # [1,2,3,4,5].cc_inject { |acc, n| acc + n } # -> 15
45
+ #
46
+ # === Explanation
47
+ #
48
+ # I've got no idea how it works. TODO: work it out. In particular, what do the arguments
49
+ # do? And what the hell is going on in #cc_inject???!?
50
+ #
51
+ # === See Also
52
+ #
53
+ # This method is included in the 'extensions' package primarily to support
54
+ # Binding.of_caller.
55
+ #
56
+ # === Credits
57
+ #
58
+ # <tt>Continuation.create</tt> was written and demonstrated by Florian Gross. See
59
+ # ruby-talk:94681.
60
+ #
61
+ def Continuation.create(*args, &block)
62
+ cc = nil
63
+ result = callcc { |c|
64
+ cc = c
65
+ block.call(cc) if block and args.empty?
66
+ }
67
+ result ||= args
68
+ return *[cc, *result]
69
+ end
70
+ end
71
+ end