live_ast 0.6.3 → 0.7.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.
data/CHANGES.rdoc CHANGED
@@ -1,6 +1,15 @@
1
1
 
2
2
  = live_ast Changes
3
3
 
4
+ == Version 0.7.0
5
+
6
+ * eval replacement option now included in the gem
7
+ * new 'boc' gem for eval replacement -- no more syntax restrictions
8
+ * add require 'live_ast/full' -- shortcut for 'live_ast' + 'live_ast/replace_eval'
9
+ * rubyspec conformance for require 'live_ast/full'
10
+ * added required_ruby_version to gemspec
11
+ * fixed error when IRB is partially required
12
+
4
13
  == Version 0.6.3
5
14
 
6
15
  * minor change for Ruby 1.9.3
data/MANIFEST CHANGED
@@ -7,12 +7,15 @@ lib/live_ast.rb
7
7
  lib/live_ast/ast_eval.rb
8
8
  lib/live_ast/ast_load.rb
9
9
  lib/live_ast/base.rb
10
+ lib/live_ast/common.rb
10
11
  lib/live_ast/error.rb
11
12
  lib/live_ast/evaler.rb
13
+ lib/live_ast/full.rb
12
14
  lib/live_ast/irb_spy.rb
13
15
  lib/live_ast/linker.rb
14
16
  lib/live_ast/loader.rb
15
17
  lib/live_ast/reader.rb
18
+ lib/live_ast/replace_eval.rb
16
19
  lib/live_ast/replace_load.rb
17
20
  lib/live_ast/replace_raise.rb
18
21
  lib/live_ast/to_ast.rb
@@ -53,6 +56,8 @@ test/readme_test.rb
53
56
  test/recursive_eval_test.rb
54
57
  test/redefine_method_test.rb
55
58
  test/reload_test.rb
59
+ test/replace_eval_test.rb
60
+ test/rubyspec_test.rb
56
61
  test/stdlib_test.rb
57
62
  test/thread_test.rb
58
63
  test/to_ast_feature_test.rb
data/README.rdoc CHANGED
@@ -3,8 +3,7 @@
3
3
 
4
4
  == Summary
5
5
 
6
- A pure Ruby library for obtaining live abstract syntax trees of
7
- methods and procs.
6
+ Live abstract syntax trees of methods and procs.
8
7
 
9
8
  == Synopsis
10
9
 
@@ -18,15 +17,12 @@ methods and procs.
18
17
 
19
18
  #### ASTs of methods
20
19
 
21
- m = Greet.instance_method(:default)
22
-
23
- p m.to_ast
20
+ p Greet.instance_method(:default).to_ast
24
21
  # => s(:defn, :default, s(:args), s(:scope, s(:block, s(:str, "hello"))))
25
22
 
26
23
  #### ASTs of lambdas, procs, blocks
27
24
 
28
25
  f = lambda { "foo" }
29
-
30
26
  p f.to_ast
31
27
  # => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "foo"))
32
28
 
@@ -39,18 +35,27 @@ methods and procs.
39
35
  "bar"
40
36
  end
41
37
 
42
- #### ASTs from dynamic code
38
+ #### ASTs from dynamic code -- fully integrated version
43
39
 
44
- f = ast_eval "lambda { 'dynamic' }", binding
40
+ require 'live_ast/full'
45
41
 
42
+ f = eval "lambda { 'dynamic1' }"
46
43
  p f.to_ast
47
- # => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic"))
44
+ # => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic1"))
45
+
46
+ eval "def g ; 'dynamic2' ; end"
47
+ p method(:g).to_ast
48
+ # => s(:defn, :g, s(:args), s(:scope, s(:block, s(:str, "dynamic2"))))
49
+
50
+ #### ASTs from dynamic code -- pure ruby version
48
51
 
49
- ast_eval "def g ; 'dynamic' ; end", binding
50
- m = method(:g)
52
+ u = ast_eval "lambda { 'dynamic3' }", binding
53
+ p u.to_ast
54
+ # => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic3"))
51
55
 
52
- p m.to_ast
53
- # => s(:defn, :g, s(:args), s(:scope, s(:block, s(:str, "dynamic"))))
56
+ ast_eval "def v ; 'dynamic4' ; end", binding
57
+ p method(:v).to_ast
58
+ # => s(:defn, :v, s(:args), s(:scope, s(:block, s(:str, "dynamic4"))))
54
59
 
55
60
  == Install
56
61
 
@@ -64,20 +69,19 @@ Or from inside an unpacked .tgz download, <code>rake install</code> /
64
69
  LiveAST enables a program to find the ASTs of objects created by
65
70
  dynamically generated code. It may be used in a strictly noninvasive
66
71
  manner, where no standard classes or methods are modified, or it may
67
- be transparently integrated into Ruby (experimental). The default
68
- setting is in between.
72
+ be transparently integrated into Ruby. The default setting is in
73
+ between.
69
74
 
70
- RubyParser is responsible for parsing and building the ASTs, though
71
- another parser may be easily substituted (in fact the name +to_ast+ is
72
- used instead of +to_sexp+ because LiveAST has no understanding of what
73
- the parser outputs).
75
+ RubyParser is the default parsing engine. To replace it with Ripper,
76
+ <code>gem install live_ast_ripper</code> and then <code>require
77
+ 'live_ast_ripper'</code>. A simple plug-in interface allows LiveAST to
78
+ work with any parser.
74
79
 
75
- Note that RubyParser does not currently support the newer Ruby 1.9
76
- syntax features (<code>Racc::ParseError</code> will be raised).
77
-
78
- To use the Ripper parser instead, <code>gem install
79
- live_ast_ripper</code> and then <code>require
80
- 'live_ast_ripper'</code>.
80
+ The advantage of RubyParser is that it gives the traditional ParseTree
81
+ sexps used by tools such as <code>ruby2ruby</code>. The disadvantage
82
+ is that the newer Ruby 1.9 syntax is not supported. However the 1.8
83
+ syntax restriction only applies to files from which ASTs are actually
84
+ requested. All other files may use 1.9 syntax.
81
85
 
82
86
  LiveAST is thread-safe.
83
87
 
@@ -92,15 +96,14 @@ Ruby 1.9.2 or higher is required.
92
96
 
93
97
  == +to_ruby+
94
98
 
95
- Although +ruby2ruby+ is not required by default,
99
+ When the default parser is active,
96
100
 
97
101
  require 'live_ast/to_ruby'
98
102
 
99
- will require +ruby2ruby+ and define the +to_ruby+ method for +Method+,
100
- +UnboundMethod+, and +Proc+. These methods are one-liners which pass
101
- the extracted ASTs to +ruby2ruby+.
103
+ will define the +to_ruby+ method for the +Method+, +UnboundMethod+,
104
+ and +Proc+ classes. These methods are one-liners which pass the
105
+ extracted ASTs to <code>ruby2ruby</code>.
102
106
 
103
- require 'live_ast'
104
107
  require 'live_ast/to_ruby'
105
108
 
106
109
  p lambda { |x, y| x + y }.to_ruby # => "lambda { |x, y| (x + y) }"
@@ -114,38 +117,50 @@ the extracted ASTs to +ruby2ruby+.
114
117
  p A.instance_method(:f).to_ruby # => "def f\n \"A#f\"\nend"
115
118
 
116
119
  In general, +to_ruby+ will hook into the unparser provided by the
117
- parser, if one is found.
120
+ parser plug-in, if one is found.
118
121
 
119
- == Loading Source
122
+ == Pure Ruby and +ast_eval+
120
123
 
121
- Objects created via +require+ and +load+ will be AST-accessible.
122
- However +ast_eval+ must be used instead of +eval+ for AST-accessible
123
- objects. +ast_eval+ has the same semantics as +eval+ except that the
124
- binding argument is required.
124
+ An essential feature of <code>require 'live_ast'</code> is that it is
125
+ implemented in pure ruby. However since pure ruby is not powerful
126
+ enough to replace +eval+, one must use +ast_eval+ instead of +eval+
127
+ for AST-accessible objects. +ast_eval+ has the same semantics as
128
+ +eval+ except that the binding argument is required.
125
129
 
126
130
  require 'live_ast'
131
+
132
+ u = ast_eval "lambda { 'dynamic3' }", binding
133
+ p u.to_ast
134
+ # => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic3"))
127
135
 
128
- class A
129
- ast_eval %{
130
- def f
131
- "A#f"
132
- end
133
-
134
- # nested evals OK
135
- ast_eval %{
136
- def g
137
- "A#g"
138
- end
139
- }, binding
140
-
141
- }, binding
142
- end
136
+ == Full integration
143
137
 
144
- p A.instance_method(:f).to_ast
145
- # => s(:defn, :f, s(:args), s(:scope, s(:block, s(:str, "A#f"))))
138
+ In order for LiveAST to be transparent to the user, +eval+ must be
139
+ replaced. This requires the +boc+ gem (http://quix.github.com/boc)
140
+ which at present only targets MRI 1.9.2 (other platforms are planned).
141
+
142
+ To replace +eval+,
143
+
144
+ % gem install boc
145
+
146
+ and then
147
+
148
+ require 'live_ast/full'
146
149
 
147
- p A.instance_method(:g).to_ast
148
- # => s(:defn, :g, s(:args), s(:scope, s(:block, s(:str, "A#g"))))
150
+ The new AST-electrified +eval+, +instance_eval+, +module_eval+,
151
+ +class_eval+, and <code>Binding#eval</code> all pass RubySpec
152
+ (http://rubyspec.org) with the minor exception of backtraces sometimes
153
+ not matching that of the original +eval+. See the "Backtraces" section
154
+ below for details.
155
+
156
+ require 'live_ast/full'
157
+
158
+ f = eval "lambda { 'dynamic1' }"
159
+ p f.to_ast
160
+ # => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic1"))
161
+
162
+ Since LiveAST itself is pure ruby, any new platforms supported by
163
+ +boc+ will automatically work with <code>live_ast/full</code>.
149
164
 
150
165
  == Limitations
151
166
 
@@ -173,6 +188,49 @@ You can probably skip these next sections. Goodbye.
173
188
 
174
189
  ----
175
190
 
191
+ == Backtraces
192
+
193
+ +ast_eval+ is meant to be compatible with +eval+. For instance the
194
+ first line of +ast_eval+'s backtrace should be identical to that of
195
+ +eval+:
196
+
197
+ require 'live_ast'
198
+
199
+ ast_eval %{ raise "boom" }, binding
200
+ # => test.rb:3:in `<main>': boom (RuntimeError)
201
+
202
+ Let's make a slight change,
203
+
204
+ require 'live_ast'
205
+
206
+ f = ast_eval %{ lambda { raise "boom" } }, binding
207
+ f.call
208
+ # => test.rb|ast@a:3:in `block in <main>': boom (RuntimeError)
209
+
210
+ What the heck is '<code>|ast@a</code>' doing there? LiveAST's
211
+ implementation has just been exposed: each source input is assigned a
212
+ unique key which enables a Ruby object to find its own definition.
213
+
214
+ In the first case above, +ast_eval+ has removed the key from the
215
+ exception backtrace. But in the second case there is no opportunity to
216
+ remove it since +ast_eval+ has already returned.
217
+
218
+ If you find this to be problem---for example if you cannot add a
219
+ filter for the jump-to-location feature in your editor---then +raise+
220
+ may be redefined to strip these tokens,
221
+
222
+ require 'live_ast'
223
+ require 'live_ast/replace_raise'
224
+
225
+ f = ast_eval %{ lambda { raise "boom" } }, binding
226
+ f.call
227
+ # => test.rb:4:in `block in <main>': boom (RuntimeError)
228
+
229
+ However this only applies to a +raise+ call originating from Ruby
230
+ code. An exception from within a native method will likely still
231
+ contain the token in its backtrace (e.g., in MRI the exception raised
232
+ by <code>1/0</code> comes from C).
233
+
176
234
  == Replacing the Parser
177
235
 
178
236
  Despite its name, LiveAST knows nothing about ASTs. It merely reports
@@ -180,7 +238,7 @@ what it finds in the line-to-AST hash returned by the parser's +parse+
180
238
  method. Replacing the parser class is therefore easy: the only
181
239
  specification is that the +parse+ instance method return such a hash.
182
240
 
183
- To override the default parser,
241
+ To override the default parser with your own,
184
242
 
185
243
  LiveAST.parser = YourParser
186
244
 
@@ -274,9 +332,10 @@ paranoia; the noninvasive option may be the most appropriate.
274
332
 
275
333
  +ast_eval+ and +load+ cache all incoming code, while
276
334
  <code>require</code>d files are cached on a need-to-know basis. When
277
- an AST is requested, the corresponding source is parsed and discarded,
278
- leaving behind method and block ASTs. +to_ast+ removes an AST from the
279
- cache and attaches it to the appropriate object (a Proc or Module).
335
+ an AST is requested, the corresponding source file is parsed and
336
+ discarded, leaving behind method and block ASTs. +to_ast+ removes an
337
+ AST from the cache and attaches it to the appropriate object (a Proc
338
+ or Module).
280
339
 
281
340
  Ignored, unextracted ASTs will therefore linger in the cache. Since
282
341
  sexps are generally small there is little need for concern unless one
@@ -311,69 +370,6 @@ only once. Furthermore, if a file has not been reloaded then it is
311
370
  assumed that the file is unmodified between the moment it is
312
371
  <code>require</code>d and the moment the first AST is pulled from it.
313
372
 
314
- == Backtraces
315
-
316
- +ast_eval+ is meant to be compatible with +eval+. For instance the
317
- first line of +ast_eval+'s backtrace should be identical to that of
318
- +eval+:
319
-
320
- require 'live_ast'
321
-
322
- ast_eval %{ raise "boom" }, binding
323
- # => test.rb:3:in `<main>': boom (RuntimeError)
324
-
325
- Let's make a slight change,
326
-
327
- require 'live_ast'
328
-
329
- f = ast_eval %{ lambda { raise "boom" } }, binding
330
- f.call
331
- # => test.rb|ast@a:3:in `block in <main>': boom (RuntimeError)
332
-
333
- What the heck is '<code>|ast@a</code>' doing there? LiveAST's
334
- implementation has just been exposed: each source input is assigned a
335
- unique key which enables a Ruby object to find its own definition.
336
-
337
- In the first case above, +ast_eval+ has removed the key from the
338
- exception backtrace. But in the second case there is no opportunity to
339
- remove it since +ast_eval+ has already returned.
340
-
341
- If you find this to be problem---for example if you cannot add a
342
- filter for the jump-to-location feature in your editor---then +raise+
343
- may be redefined to strip these tokens,
344
-
345
- require 'live_ast'
346
- require 'live_ast/replace_raise'
347
-
348
- f = ast_eval %{ lambda { raise "boom" } }, binding
349
- f.call
350
- # => test.rb:4:in `block in <main>': boom (RuntimeError)
351
-
352
- However this only applies to a +raise+ call originating from Ruby
353
- code. An exception raised within a native method will likely still
354
- contain the token in its backtrace (e.g., in MRI the exception raised
355
- by <code>1/0</code> comes from C). In principle this could be fixed by
356
- having the Ruby interpreter dynamically call +raise+.
357
-
358
-
359
- == Replacing +eval+
360
-
361
- If +ast_eval+ did not require a binding argument then it could assume
362
- the role of +eval+, thereby making LiveAST fully transparent to the
363
- user. Is this possible in pure Ruby?
364
-
365
- The only option which has been investigated thus far is MRI, which can
366
- summon <code>Binding.of_caller</code> (recently rewritten for 1.9.2)
367
- to fill in the missing binding argument. Unfortunately a limitation
368
- with tracing events in MRI places a few odd restrictions on the syntax
369
- surrounding +eval+, though all restrictions can be trivially
370
- sidestepped. Nonetheless it does work (it passes rubyspec minus the
371
- above backtrace issue) despite being somewhat impractical.
372
-
373
- This (mis)feature is maintained in a separate branch named
374
- +replace_eval+ on github (not part of the gem). For more information see
375
- replace_eval.rb[http://github.com/quix/live_ast/blob/replace_eval/lib/live_ast/replace_eval.rb].
376
-
377
373
  == Author
378
374
 
379
375
  * James M. Lawrence < quixoticsycophant@gmail.com >
data/Rakefile CHANGED
@@ -2,11 +2,11 @@ require_relative 'devel/levitate'
2
2
 
3
3
  Levitate.new "live_ast" do |s|
4
4
  s.developers << ["James M. Lawrence", "quixoticsycophant@gmail.com"]
5
- s.github_user = "quix"
5
+ s.username = "quix"
6
6
  s.rubyforge_info = ["quix", "liveast"]
7
7
  s.camel_name = "LiveAST"
8
-
9
- s.rdoc_title = "LiveAST: Live Abstract Syntax Trees"
8
+ s.required_ruby_version = ">= 1.9.2"
9
+ s.dependencies << ["live_ast_ruby_parser", ">= 0.6.0"]
10
10
  s.rdoc_files = %w[
11
11
  lib/live_ast/ast_eval.rb
12
12
  lib/live_ast/base.rb
@@ -15,6 +15,4 @@ Levitate.new "live_ast" do |s|
15
15
  lib/live_ast/version.rb
16
16
  ]
17
17
  s.rdoc_options << "-a"
18
-
19
- s.dependencies << ["live_ast_ruby_parser", ">= 0.6.0"]
20
18
  end
data/devel/levitate.rb CHANGED
@@ -219,31 +219,18 @@ class Levitate
219
219
  }
220
220
  contents
221
221
  end
222
- end
223
-
224
- module InstanceEvalWithArgs
225
- module_function
226
222
 
227
- def with_temp_method(instance, method_name, method_block)
228
- (class << instance ; self ; end).class_eval do
229
- define_method(method_name, &method_block)
223
+ def instance_exec2(obj, *args, &block)
224
+ method_name = ["_", obj.object_id, "_", Thread.current.object_id].join
225
+ (class << obj ; self ; end).class_eval do
226
+ define_method method_name, &block
230
227
  begin
231
- yield method_name
228
+ obj.send(method_name, *args)
232
229
  ensure
233
- remove_method(method_name)
230
+ remove_method method_name
234
231
  end
235
232
  end
236
233
  end
237
-
238
- def call_temp_method(instance, method_name, *args, &method_block)
239
- with_temp_method(instance, method_name, method_block) {
240
- instance.send(method_name, *args)
241
- }
242
- end
243
-
244
- def instance_eval_with_args(instance, *args, &block)
245
- call_temp_method(instance, :__temp_method, *args, &block)
246
- end
247
234
  end
248
235
 
249
236
  include AttrLazy
@@ -296,6 +283,10 @@ class Levitate
296
283
  mod.const_get(version_constant_name)
297
284
  end or "0.0.0"
298
285
  end
286
+
287
+ attribute :required_ruby_version do
288
+ ">= 0"
289
+ end
299
290
 
300
291
  attribute :readme_file do
301
292
  "README.rdoc"
@@ -362,6 +353,10 @@ class Levitate
362
353
  []
363
354
  end
364
355
 
356
+ attribute :extra_gemspec do
357
+ lambda { |spec| }
358
+ end
359
+
365
360
  attribute :files do
366
361
  if File.file? manifest_file
367
362
  File.read(manifest_file).split("\n")
@@ -381,7 +376,7 @@ class Levitate
381
376
  end
382
377
 
383
378
  attribute :rdoc_title do
384
- "#{gem_name}: #{summary}"
379
+ "#{gem_name}: #{summary}".sub(/\.\Z/, "")
385
380
  end
386
381
 
387
382
  attribute :require_paths do
@@ -426,6 +421,8 @@ class Levitate
426
421
  rdoc_options
427
422
  extra_rdoc_files
428
423
  require_paths
424
+ required_ruby_version
425
+ extensions
429
426
  ].each do |param|
430
427
  t = send(param) and g.send("#{param}=", t)
431
428
  end
@@ -438,6 +435,7 @@ class Levitate
438
435
  development_dependencies.each { |dep|
439
436
  g.add_development_dependency(*dep)
440
437
  }
438
+ extra_gemspec.call(g)
441
439
  end
442
440
  end
443
441
 
@@ -490,22 +488,22 @@ class Levitate
490
488
  }
491
489
 
492
490
  attribute :url do
493
- "http://#{github_user}.github.com/#{gem_name}"
491
+ "http://#{username}.github.com/#{gem_name}"
494
492
  end
495
493
 
496
- attribute :github_user do
497
- raise "github_user not set"
494
+ attribute :username do
495
+ raise "username not set"
498
496
  end
499
497
 
500
498
  attribute :rubyforge_info do
501
499
  nil
502
500
  end
503
501
 
504
- attribute :authors do
502
+ def authors
505
503
  developers.map { |d| d[0] }
506
504
  end
507
505
 
508
- attribute :email do
506
+ def email
509
507
  developers.map { |d| d[1] }
510
508
  end
511
509
 
@@ -521,6 +519,10 @@ class Levitate
521
519
  []
522
520
  end
523
521
 
522
+ attribute :extensions do
523
+ ["ext/#{gem_name}/extconf.rb"].select { |f| File.file? f }
524
+ end
525
+
524
526
  def define_clean
525
527
  require 'rake/clean'
526
528
  task :clean do
@@ -800,6 +802,35 @@ class Levitate
800
802
  puts gemspec.to_ruby
801
803
  end
802
804
  end
805
+
806
+ def define_extension
807
+ unless extensions.empty?
808
+ require 'rbconfig'
809
+ require 'rake/extensiontask'
810
+
811
+ Rake::ExtensionTask.new gem_name, gemspec do |ext|
812
+ ext.cross_compile = true
813
+ ext.cross_platform = 'i386-mswin32'
814
+ ext.cross_compiling do |gemspec|
815
+ gemspec.post_install_message =
816
+ "U got dat binary versionation of this gemination!"
817
+ end
818
+ end
819
+
820
+ so = "lib/#{gem_name}.#{RbConfig::CONFIG["DLEXT"]}"
821
+ if Rake::Task[so].needed?
822
+ task :test => so
823
+ end
824
+
825
+ task :cross_native_gem do
826
+ Rake::Task[:gem].reenable
827
+ Rake.application.top_level_tasks.replace %w[cross native gem]
828
+ Rake.application.top_level
829
+ end
830
+
831
+ task :gem => :cross_native_gem
832
+ end
833
+ end
803
834
 
804
835
  def open_browser(*files)
805
836
  sh(*([browser].flatten + files))
@@ -827,7 +858,6 @@ class Levitate
827
858
 
828
859
  class << self
829
860
  include Util
830
- include InstanceEvalWithArgs
831
861
 
832
862
  # From minitest, part of the Ruby source; by Ryan Davis.
833
863
  def capture_io
@@ -867,7 +897,7 @@ class Levitate
867
897
  actual = Ruby.run_file_and_capture(temp_file.path).chomp
868
898
  }
869
899
 
870
- instance_eval_with_args(instance, expected, actual, index, &block)
900
+ instance_exec2(instance, expected, actual, index, &block)
871
901
  end
872
902
 
873
903
  def run_doc_section(file, section, instance, &block)
data/lib/live_ast/base.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'thread'
2
2
 
3
+ require 'live_ast/common'
3
4
  require 'live_ast/reader'
4
5
  require 'live_ast/evaler'
5
6
  require 'live_ast/linker'
@@ -61,5 +62,12 @@ module LiveAST
61
62
  def load(file, wrap = false) #:nodoc:
62
63
  Loader.load(file, wrap)
63
64
  end
65
+
66
+ #
67
+ # strip the revision token from a string
68
+ #
69
+ def strip_token(file) #:nodoc:
70
+ file.sub(/#{Regexp.quote Linker::REVISION_TOKEN}[a-z]+/, "")
71
+ end
64
72
  end
65
73
  end
@@ -0,0 +1,48 @@
1
+
2
+ module LiveAST
3
+ module Common
4
+ module_function
5
+
6
+ def arg_to_str(arg)
7
+ begin
8
+ arg.to_str
9
+ rescue NameError
10
+ thing = if arg.nil? then nil else arg.class end
11
+
12
+ raise TypeError, "can't convert #{thing.inspect} into String"
13
+ end
14
+ end
15
+
16
+ def check_arity(args, range)
17
+ unless range.include? args.size
18
+ range = 0 if range == (0..0)
19
+
20
+ raise ArgumentError,
21
+ "wrong number of arguments (#{args.size} for #{range})"
22
+ end
23
+ end
24
+
25
+ def check_type(obj, klass)
26
+ unless obj.is_a? klass
27
+ raise TypeError, "wrong argument type #{obj.class} (expected #{klass})"
28
+ end
29
+ end
30
+
31
+ def location_for_eval(*args)
32
+ bind, *location = args
33
+
34
+ if bind
35
+ case location.size
36
+ when 0
37
+ NATIVE_EVAL.call("[__FILE__, __LINE__]", bind)
38
+ when 1
39
+ [location.first, 1]
40
+ else
41
+ location
42
+ end
43
+ else
44
+ ["(eval)", 1]
45
+ end
46
+ end
47
+ end
48
+ end