ruby18_source_location 0.2-i386-mingw32
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/.gitignore +5 -0
- data/LICENSE.MIT +19 -0
- data/README.md +38 -0
- data/Rakefile +46 -0
- data/ext/extconf.rb +7 -0
- data/ext/ruby18_source_location.c +158 -0
- data/ruby18_source_location.gemspec +14 -0
- data/test/examples.rb +64 -0
- data/test/test_ruby18_source_location.rb +106 -0
- metadata +75 -0
data/LICENSE.MIT
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2011 Conrad Irwin <conrad.irwin@gmail.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
The `ruby18_source_location` gem backports the `source_location` instance method of `Method`, `UnboundMethod` and
|
2
|
+
`Proc` from Ruby 1.9.
|
3
|
+
|
4
|
+
This allows you to use `Method#source_location` on ruby 1.8.7, and also all the other gems that depend on it.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
-----
|
8
|
+
|
9
|
+
gem install ruby18_source_location
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'rubygems'
|
13
|
+
require 'ruby18_source_location'
|
14
|
+
|
15
|
+
def example
|
16
|
+
2
|
17
|
+
end
|
18
|
+
|
19
|
+
puts method(:example).source_location.inspect
|
20
|
+
# => ["/tmp/example.rb", 4]
|
21
|
+
|
22
|
+
puts Proc.new{}.source_location.inspect
|
23
|
+
# => ["/tmp/example.rb", 11]
|
24
|
+
|
25
|
+
puts method(:puts).source_location.inspect
|
26
|
+
# => nil
|
27
|
+
```
|
28
|
+
|
29
|
+
Known issues
|
30
|
+
------------
|
31
|
+
|
32
|
+
Under Ruby-1.8.7, it's not currently possible to get the `source_location` of methods defined by `attr_reader`,
|
33
|
+
`attr_writer` or `attr_accessor`, unless you are running Ruby Enterprise Edition.
|
34
|
+
|
35
|
+
Meta-foo
|
36
|
+
--------
|
37
|
+
|
38
|
+
This is made available under the MIT license (see LICENSE.MIT), contributions and bug reports are welcome.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
def dir(*args); Dir.chdir(File.join(File.dirname(__FILE__), *args)); end
|
3
|
+
|
4
|
+
desc "Compile local copy"
|
5
|
+
task :compile do
|
6
|
+
cd("ext") do
|
7
|
+
system "ruby extconf.rb"
|
8
|
+
system "make"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
task :clean do
|
13
|
+
cd("ext") do
|
14
|
+
system "make clean"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Package the gem"
|
19
|
+
task :gem do
|
20
|
+
dir('.')
|
21
|
+
system "gem build ruby18_source_location.gemspec"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Package the windows gem"
|
25
|
+
task :win_gem => [:clean, :compile] do
|
26
|
+
dir = File.dirname(__FILE__)
|
27
|
+
cd(dir) do
|
28
|
+
system "cp #{dir}/ext/*.so #{dir}/lib/"
|
29
|
+
system "gem build ruby18_source_location_mswin32.gemspec"
|
30
|
+
system "gem build ruby18_source_location_mingw32.gemspec"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Run the tests"
|
35
|
+
task :test do
|
36
|
+
dir("test")
|
37
|
+
system "ruby test_ruby18_source_location.rb"
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Run an interactive shell"
|
41
|
+
task :pry do
|
42
|
+
dir('.')
|
43
|
+
system "pry -f -r ext/ruby18_source_location -r test/examples"
|
44
|
+
end
|
45
|
+
|
46
|
+
task :default => [:clean, :compile, :test]
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "node.h"
|
3
|
+
|
4
|
+
// Cargo-culted from ruby internal headers.
|
5
|
+
struct FRAME {
|
6
|
+
VALUE self;
|
7
|
+
int argc;
|
8
|
+
ID last_func;
|
9
|
+
ID orig_func;
|
10
|
+
VALUE last_class;
|
11
|
+
struct FRAME *prev;
|
12
|
+
struct FRAME *tmp;
|
13
|
+
struct RNode *node;
|
14
|
+
int iter;
|
15
|
+
int flags;
|
16
|
+
unsigned long uniq;
|
17
|
+
} *ruby_frame;
|
18
|
+
|
19
|
+
struct METHOD {
|
20
|
+
VALUE klass, rklass;
|
21
|
+
VALUE recv;
|
22
|
+
ID id, oid;
|
23
|
+
int safe_level;
|
24
|
+
NODE *body;
|
25
|
+
};
|
26
|
+
|
27
|
+
struct BLOCK {
|
28
|
+
NODE *var;
|
29
|
+
NODE *body;
|
30
|
+
VALUE self;
|
31
|
+
struct FRAME frame;
|
32
|
+
struct SCOPE *scope;
|
33
|
+
VALUE klass;
|
34
|
+
NODE *cref;
|
35
|
+
int iter;
|
36
|
+
int vmode;
|
37
|
+
int flags;
|
38
|
+
int uniq;
|
39
|
+
struct RVarmap *dyna_vars;
|
40
|
+
VALUE orig_thread;
|
41
|
+
VALUE wrapper;
|
42
|
+
VALUE block_obj;
|
43
|
+
struct BLOCK *outer;
|
44
|
+
struct BLOCK *prev;
|
45
|
+
};
|
46
|
+
|
47
|
+
|
48
|
+
static VALUE method_source_location(VALUE);
|
49
|
+
static VALUE proc_source_location(VALUE);
|
50
|
+
|
51
|
+
void
|
52
|
+
Init_ruby18_source_location()
|
53
|
+
{
|
54
|
+
rb_define_method(rb_cUnboundMethod, "source_location", method_source_location, 0);
|
55
|
+
rb_define_method(rb_cMethod, "source_location", method_source_location, 0);
|
56
|
+
rb_define_method(rb_cProc, "source_location", proc_source_location, 0);
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE
|
60
|
+
node_source_location(NODE *node)
|
61
|
+
{
|
62
|
+
const char *filename = node->nd_file;
|
63
|
+
int lineno = nd_line(node);
|
64
|
+
|
65
|
+
if (filename && lineno) {
|
66
|
+
VALUE str = rb_str_new2(filename);
|
67
|
+
|
68
|
+
// TODO: is there a better way of telling whether the file should be absolute
|
69
|
+
if (Qtrue == rb_funcall(rb_cFile, rb_intern("exist?"), 1, str))
|
70
|
+
str = rb_file_expand_path(str, Qnil);
|
71
|
+
|
72
|
+
return rb_assoc_new(str, INT2FIX(lineno));
|
73
|
+
}
|
74
|
+
|
75
|
+
rb_raise(rb_eRuntimeError, "source_location: no file for node");
|
76
|
+
}
|
77
|
+
|
78
|
+
/*
|
79
|
+
* call-seq:
|
80
|
+
* meth.source_location => [String, Fixnum]
|
81
|
+
*
|
82
|
+
* returns a pair of the Filename and line number on which the method is defined
|
83
|
+
*
|
84
|
+
* returns nil if method has no associated ruby source code
|
85
|
+
*/
|
86
|
+
static VALUE
|
87
|
+
method_source_location(VALUE method)
|
88
|
+
{
|
89
|
+
struct METHOD *data;
|
90
|
+
struct BLOCK *block;
|
91
|
+
NODE *node;
|
92
|
+
|
93
|
+
Data_Get_Struct(method, struct METHOD, data);
|
94
|
+
|
95
|
+
if (!(node = data->body))
|
96
|
+
rb_raise(rb_eRuntimeError, "source_location: no body for method");
|
97
|
+
|
98
|
+
switch (nd_type(node)) {
|
99
|
+
// methods defined by C extensions
|
100
|
+
case NODE_CFUNC:
|
101
|
+
return Qnil;
|
102
|
+
|
103
|
+
// attr_accessor :foo
|
104
|
+
case NODE_IVAR: // method(:foo)
|
105
|
+
case NODE_ATTRSET: // method(:foo=)
|
106
|
+
|
107
|
+
// ruby enterpise edition fixes nd_line on these nodes
|
108
|
+
#ifdef MBARI_API
|
109
|
+
return node_source_location(node);
|
110
|
+
#else
|
111
|
+
// FIXME, Ruby-1.8.7 returns a bad nd_line on these.
|
112
|
+
return Qnil;
|
113
|
+
#endif
|
114
|
+
|
115
|
+
// def foo; end
|
116
|
+
case NODE_SCOPE:
|
117
|
+
return node_source_location((NODE *)node->u3.value);
|
118
|
+
|
119
|
+
// define_method(:foo, method(:bar))
|
120
|
+
case NODE_DMETHOD:
|
121
|
+
return method_source_location(node->u3.value);
|
122
|
+
|
123
|
+
// define_method(:foo) { }, define_method(:foo, &bar)
|
124
|
+
case NODE_BMETHOD:
|
125
|
+
return proc_source_location(node->u3.value);
|
126
|
+
|
127
|
+
default:
|
128
|
+
rb_raise(rb_eRuntimeError, "source_location: unhandled method type %d", nd_type(node));
|
129
|
+
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
/*
|
134
|
+
* call-seq:
|
135
|
+
* proc.source_location => [String, Fixnum]
|
136
|
+
*
|
137
|
+
* returns a pair of the Filename and line number on which the method is defined
|
138
|
+
*
|
139
|
+
* returns nil if method has no associated ruby source code
|
140
|
+
*/
|
141
|
+
static VALUE
|
142
|
+
proc_source_location(VALUE block)
|
143
|
+
{
|
144
|
+
struct BLOCK *data;
|
145
|
+
NODE *node;
|
146
|
+
Data_Get_Struct(block, struct BLOCK, data);
|
147
|
+
|
148
|
+
// Proc.new {}, or Proc.new &proc
|
149
|
+
if ((node = data->frame.node) && nd_type(node) == NODE_ITER)
|
150
|
+
return node_source_location(node);
|
151
|
+
|
152
|
+
// Proc.new &method(:foo)
|
153
|
+
if ((node = data->body) && nd_type(node) == NODE_IFUNC)
|
154
|
+
return method_source_location(node->u2.value);
|
155
|
+
|
156
|
+
rb_raise(rb_eRuntimeError, "source_location: unhandled proc type");
|
157
|
+
|
158
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = "ruby18_source_location"
|
4
|
+
s.version = "0.2"
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.author = "Conrad Irwin"
|
7
|
+
s.email = "conrad.irwin@gmail.com"
|
8
|
+
s.homepage = "http://github.com/ConradIrwin/ruby18_source_location"
|
9
|
+
s.summary = "Add .source_location to methods in Ruby 1.8.7"
|
10
|
+
s.description = "Allows you to make use of lots of ruby 1.9.2 specific goodness"
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.extensions = "ext/extconf.rb"
|
13
|
+
s.require_path = "ext"
|
14
|
+
end
|
data/test/examples.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
class Example
|
2
|
+
|
3
|
+
def example1
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
define_method(:example2) {
|
8
|
+
|
9
|
+
}
|
10
|
+
|
11
|
+
Example3 = Proc.new do
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
Example4 = lambda {
|
16
|
+
|
17
|
+
}
|
18
|
+
|
19
|
+
define_method(:example5, Example3)
|
20
|
+
|
21
|
+
define_method(:example6, &Example4)
|
22
|
+
|
23
|
+
define_method(:example7, instance_method(:example1))
|
24
|
+
|
25
|
+
define_method(:example8, &Example.new.method(:example2))
|
26
|
+
|
27
|
+
Example9 = Proc.new &Example3
|
28
|
+
|
29
|
+
Example10 = Proc.new &Example.new.method(:example1)
|
30
|
+
|
31
|
+
eval <<-EVAL
|
32
|
+
def example11
|
33
|
+
|
34
|
+
end
|
35
|
+
EVAL
|
36
|
+
|
37
|
+
eval <<-EVAL, binding, __FILE__, __LINE__+1
|
38
|
+
def example12
|
39
|
+
|
40
|
+
end
|
41
|
+
EVAL
|
42
|
+
|
43
|
+
def self.example13
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
alias example14 example1
|
48
|
+
|
49
|
+
alias_method :example15, :example2
|
50
|
+
|
51
|
+
attr_reader :example16
|
52
|
+
|
53
|
+
attr_accessor :example17
|
54
|
+
|
55
|
+
def example18(&block)
|
56
|
+
block
|
57
|
+
end
|
58
|
+
|
59
|
+
Example19 = lambda &method(:puts)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
# vim: number
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
puts "Testing with #{RUBY_VERSION}"
|
4
|
+
if Method.method_defined?(:source_location)
|
5
|
+
warn "using BUILTING source_location"
|
6
|
+
else
|
7
|
+
require "#{File.dirname(__FILE__)}/../ext/ruby18_source_location"
|
8
|
+
end
|
9
|
+
require "#{File.dirname(__FILE__)}/examples"
|
10
|
+
|
11
|
+
class TestRuby18SourceLocation < Test::Unit::TestCase
|
12
|
+
|
13
|
+
def assert_on_line(line, method)
|
14
|
+
assert_equal [File.expand_path('./examples.rb'), line], method.source_location
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_same_source(m1, m2)
|
18
|
+
assert_equal m1.source_location, m2.source_location
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_normal_method
|
22
|
+
assert_on_line 3, Example.instance_method(:example1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_define_method_with_block
|
26
|
+
assert_on_line 7, Example.instance_method(:example2)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_proc_new
|
30
|
+
assert_on_line 11, Example::Example3
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_lambda
|
34
|
+
assert_on_line 15, Example::Example4
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_define_method_with_proc_arg
|
38
|
+
assert_same_source Example::Example3, Example.new.method(:example5)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_define_method_with_amp_proc
|
42
|
+
assert_same_source Example::Example4, Example.new.method(:example6)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_define_method_with_method_arg
|
46
|
+
assert_same_source Example.new.method(:example1), Example.new.method(:example7)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_define_method_with_amp_method
|
50
|
+
assert_same_source Example.new.method(:example2), Example.new.method(:example8)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_proc_with_amp_proc
|
54
|
+
assert_same_source Example::Example3, Example::Example9
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_proc_with_amp_method
|
58
|
+
assert_same_source Example.instance_method(:example1), Example::Example10
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_eval
|
62
|
+
assert_equal ['(eval)', 1], Example.instance_method(:example11).source_location
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_eval_with_overridden_line
|
66
|
+
assert_on_line 38, Example.new.method(:example12)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_class_method
|
70
|
+
assert_on_line 43, Example.method(:example13)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_alias
|
74
|
+
assert_same_source Example.new.method(:example1), Example.new.method(:example14)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_alias_method
|
78
|
+
assert_same_source Example.new.method(:example2), Example.new.method(:example15)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_c_method
|
82
|
+
assert_equal nil, method(:puts).source_location
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_attr_reader
|
86
|
+
assert_on_line 51, Example.instance_method(:example16)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_attr_accessor
|
90
|
+
assert_on_line 53, Example.instance_method(:example17)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_attr_assign
|
94
|
+
assert_on_line 53, Example.instance_method(:example17=)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_blocks
|
98
|
+
assert_equal [File.expand_path(__FILE__), __LINE__], Example.new.example18{
|
99
|
+
|
100
|
+
}.source_location
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_lambdas_with_c_methods
|
104
|
+
assert_equal nil, Example::Example19.source_location
|
105
|
+
end
|
106
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby18_source_location
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: "0.2"
|
10
|
+
platform: i386-mingw32
|
11
|
+
authors:
|
12
|
+
- Conrad Irwin
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-04-13 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Allows you to make use of lots of ruby 1.9.2 specific goodness
|
22
|
+
email: conrad.irwin@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- .gitignore
|
31
|
+
- LICENSE.MIT
|
32
|
+
- README.md
|
33
|
+
- Rakefile
|
34
|
+
- ext/extconf.rb
|
35
|
+
- ext/ruby18_source_location.c
|
36
|
+
- ruby18_source_location.gemspec
|
37
|
+
- test/examples.rb
|
38
|
+
- test/test_ruby18_source_location.rb
|
39
|
+
- lib/ruby18_source_location.so
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/ConradIrwin/ruby18_source_location
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
hash: 3
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.5.2
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Add .source_location to methods in Ruby 1.8.7
|
74
|
+
test_files: []
|
75
|
+
|