glue 0.13.0 → 0.14.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.
@@ -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
+