glue 0.13.0 → 0.14.0

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