og 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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