getsource 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGELOG +1 -0
- data/README +48 -0
- data/Rakefile +49 -0
- data/TODO +0 -0
- data/examples/test1/main.rb +13 -0
- data/examples/test1/source1.rb +4 -0
- data/examples/test1/source2.rb +4 -0
- data/ext/getsource_base/extconf.rb +22 -0
- data/ext/getsource_base/getsource_base.c +212 -0
- data/lib/getsource.rb +38 -0
- metadata +78 -0
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
getsource de tario <rseminara@hotmail.com>
|
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0: implemented getsource with code extracted from rallhook
|
data/README
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= getsource - Get the source file path of the implementation of a given method =
|
2
|
+
|
3
|
+
This package cointains getsource, a extension which allows get the path name for the source of a method
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
gem install getsource
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
=== Basic Example
|
12
|
+
|
13
|
+
|
14
|
+
source1.rb
|
15
|
+
|
16
|
+
class X
|
17
|
+
def foo
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
source2.rb
|
22
|
+
|
23
|
+
class Y < X
|
24
|
+
def foo
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
main.rb
|
29
|
+
|
30
|
+
require "rallhook"
|
31
|
+
require "source1.rb"
|
32
|
+
require "source2.rb"
|
33
|
+
|
34
|
+
x = X.new
|
35
|
+
y = Y.new
|
36
|
+
|
37
|
+
print x.method(:foo).body.file,"\n" # source1.rb
|
38
|
+
print y.method(:foo).body.file,"\n" # source2.rb
|
39
|
+
|
40
|
+
print y.method(X,:foo).body.file,"\n" # source1.rb
|
41
|
+
print y.method(Y,:foo).body.file,"\n" # source2.rb
|
42
|
+
|
43
|
+
|
44
|
+
NOTE: See examples directory of the gem installation
|
45
|
+
|
46
|
+
== Copying
|
47
|
+
|
48
|
+
Copyright (c) 2010 Dario Seminara, released under the GPL License (see LICENSE)
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'getsource'
|
9
|
+
s.version = '0.1.0'
|
10
|
+
s.author = 'Dario Seminara'
|
11
|
+
s.email = 'robertodarioseminara@gmail.com'
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.summary = 'Get the source file path of the implementation of a given method'
|
14
|
+
s.homepage = "http://github.com/tario/getsource"
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.extra_rdoc_files = [ 'README' ]
|
17
|
+
s.rdoc_options << '--main' << 'README'
|
18
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
19
|
+
s.files = Dir.glob("{examples,lib,test}/**/*.rb") + Dir.glob("ext/**/*.c") + Dir.glob("ext/**/*.h") + Dir.glob("ext/**/extconf.rb") +
|
20
|
+
[ 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Run tests'
|
24
|
+
task :default => [ :test ]
|
25
|
+
|
26
|
+
Rake::TestTask.new('test') do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = '{test}/**/test_*.rb'
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Generate RDoc'
|
33
|
+
Rake::RDocTask.new :rdoc do |rd|
|
34
|
+
rd.rdoc_dir = 'doc'
|
35
|
+
rd.rdoc_files.add 'lib', 'ext', 'README'
|
36
|
+
rd.main = 'README'
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Build Gem'
|
40
|
+
Rake::GemPackageTask.new spec do |pkg|
|
41
|
+
pkg.need_tar = true
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Clean up'
|
45
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
46
|
+
|
47
|
+
desc 'Clean up'
|
48
|
+
task :clobber => [ :clean ]
|
49
|
+
|
data/TODO
ADDED
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "getsource"
|
3
|
+
require "source1.rb"
|
4
|
+
require "source2.rb"
|
5
|
+
|
6
|
+
x = X.new
|
7
|
+
y = Y.new
|
8
|
+
|
9
|
+
print "definition of method :foo in #{x}: ", x.method(:foo).body.file,"\n" # source1.rb
|
10
|
+
print "definition of method :foo in #{y}: ", y.method(:foo).body.file,"\n" # source2.rb
|
11
|
+
|
12
|
+
print "definition of method :foo of class X in object #{y}: ", y.specific_method(X,:foo).body.file,"\n" # source1.rb
|
13
|
+
print "definition of method :foo of class Y in object #{y}: ", y.specific_method(Y,:foo).body.file,"\n" # source1.rb
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
dir_config('getsource_base')
|
3
|
+
CONFIG['CC'] = 'gcc'
|
4
|
+
|
5
|
+
ruby_version = Config::CONFIG["ruby_version"]
|
6
|
+
ruby_version = ruby_version.split(".")[0..1].join(".")
|
7
|
+
|
8
|
+
if ruby_version == "1.8"
|
9
|
+
$CFLAGS = $CFLAGS + " -DRUBY1_8"
|
10
|
+
elsif ruby_version == "1.9"
|
11
|
+
$CFLAGS = $CFLAGS + " -DRUBY1_9"
|
12
|
+
else
|
13
|
+
print "ERROR: unknown ruby version: #{ruby_version}\n"
|
14
|
+
print "try passing the rubyversion by argument (1.8 or 1.9)\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
$CFLAGS = $CFLAGS + " -o $@"
|
18
|
+
|
19
|
+
create_makefile('getsource_base')
|
20
|
+
|
21
|
+
|
22
|
+
|
@@ -0,0 +1,212 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the getsource project, http://github.com/tario/getsource
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
getsource is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
getsource is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with getsource. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <ruby.h>
|
23
|
+
|
24
|
+
#ifdef RUBY1_8
|
25
|
+
#include <node.h>
|
26
|
+
#endif
|
27
|
+
|
28
|
+
#ifdef RUBY1_9
|
29
|
+
#include <node_defs.h>
|
30
|
+
#endif
|
31
|
+
|
32
|
+
#ifndef __USE_GNU
|
33
|
+
#define __USE_GNU
|
34
|
+
#endif
|
35
|
+
#include <dlfcn.h>
|
36
|
+
|
37
|
+
|
38
|
+
VALUE rb_cNode;
|
39
|
+
ID intern_owner;
|
40
|
+
ID intern_name;
|
41
|
+
ID intern_sym;
|
42
|
+
|
43
|
+
/// from eval.c
|
44
|
+
#ifdef RUBY1_8
|
45
|
+
struct METHOD {
|
46
|
+
VALUE klass, rklass;
|
47
|
+
|
48
|
+
VALUE recv;
|
49
|
+
ID id, oid;
|
50
|
+
int safe_level;
|
51
|
+
NODE *body;
|
52
|
+
};
|
53
|
+
unsigned char* base__;
|
54
|
+
|
55
|
+
#define nd_file(n) n->nd_file
|
56
|
+
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#ifdef RUBY1_9
|
60
|
+
|
61
|
+
// from proc.c
|
62
|
+
struct METHOD {
|
63
|
+
VALUE oclass; /* class that holds the method */
|
64
|
+
VALUE rclass; /* class of the receiver */
|
65
|
+
VALUE recv;
|
66
|
+
ID id, oid;
|
67
|
+
NODE *body;
|
68
|
+
};
|
69
|
+
|
70
|
+
typedef struct rb_iseq_struct__ {
|
71
|
+
VALUE type; // instruction sequence type
|
72
|
+
VALUE name; // String: iseq name
|
73
|
+
VALUE filename; // file information where this sequence from
|
74
|
+
} rb_iseq_t__;
|
75
|
+
|
76
|
+
|
77
|
+
typedef VALUE (*MNEW)(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope);
|
78
|
+
MNEW mnew_;
|
79
|
+
unsigned char* base__;
|
80
|
+
|
81
|
+
#endif
|
82
|
+
|
83
|
+
/*
|
84
|
+
The node that acts as body of the method
|
85
|
+
*/
|
86
|
+
VALUE rb_method_body(VALUE self) {
|
87
|
+
|
88
|
+
// VALUE name = rb_funcall(self, intern_name, 0);
|
89
|
+
// VALUE sym = rb_funcall(name, intern_sym, 0);
|
90
|
+
// VALUE owner = rb_funcall(self, intern_owner, 0);
|
91
|
+
// NODE* body = rb_method_node(owner, SYM2ID(sym) );
|
92
|
+
|
93
|
+
struct METHOD* method;
|
94
|
+
Data_Get_Struct(self,struct METHOD,method);
|
95
|
+
|
96
|
+
if (method->body == 0) return Qnil;
|
97
|
+
|
98
|
+
#ifdef RUBY1_8
|
99
|
+
// nd_defn is only present in ruby_1.8
|
100
|
+
if (method->body->nd_defn != 0) {
|
101
|
+
return Data_Wrap_Struct(rb_cNode, 0, 0, method->body->nd_defn);
|
102
|
+
}
|
103
|
+
#endif
|
104
|
+
|
105
|
+
return Data_Wrap_Struct(rb_cNode, 0, 0, method->body);
|
106
|
+
}
|
107
|
+
|
108
|
+
/*
|
109
|
+
The number of the line where the code associated with note are defined in the ruby source file
|
110
|
+
*/
|
111
|
+
VALUE rb_node_line(VALUE self) {
|
112
|
+
NODE* _node;
|
113
|
+
Data_Get_Struct(self,NODE,_node);
|
114
|
+
|
115
|
+
#ifdef RUBY1_8
|
116
|
+
return INT2FIX(nd_line(_node));
|
117
|
+
#endif
|
118
|
+
|
119
|
+
#ifdef RUBY1_9
|
120
|
+
return INT2FIX(0);
|
121
|
+
#endif
|
122
|
+
}
|
123
|
+
|
124
|
+
/*
|
125
|
+
The name of the ruby source file where the code associated with the node are defined
|
126
|
+
*/
|
127
|
+
VALUE rb_node_file(VALUE self) {
|
128
|
+
NODE* _node;
|
129
|
+
Data_Get_Struct(self,NODE,_node);
|
130
|
+
|
131
|
+
#ifdef RUBY1_8
|
132
|
+
if (nd_file(_node) == NULL ) {
|
133
|
+
return rb_str_new2("");
|
134
|
+
}
|
135
|
+
return rb_str_new2(nd_file(_node) );
|
136
|
+
#endif
|
137
|
+
|
138
|
+
#ifdef RUBY1_9
|
139
|
+
|
140
|
+
if (nd_type(_node) == RUBY_VM_METHOD_NODE) {
|
141
|
+
VALUE iseqval = (VALUE)(_node->nd_body);
|
142
|
+
rb_iseq_t__* ptr;
|
143
|
+
Data_Get_Struct(iseqval, rb_iseq_t__, ptr);
|
144
|
+
|
145
|
+
return ptr->filename;
|
146
|
+
}
|
147
|
+
|
148
|
+
return rb_str_new2("");
|
149
|
+
|
150
|
+
#endif
|
151
|
+
|
152
|
+
}
|
153
|
+
|
154
|
+
|
155
|
+
static void
|
156
|
+
bm_mark(struct METHOD *data)
|
157
|
+
{
|
158
|
+
#ifdef RUBY1_8
|
159
|
+
rb_gc_mark(data->klass);
|
160
|
+
rb_gc_mark(data->rklass);
|
161
|
+
rb_gc_mark(data->recv);
|
162
|
+
rb_gc_mark((VALUE)data->body);
|
163
|
+
#endif
|
164
|
+
#ifdef RUBY1_9
|
165
|
+
rb_gc_mark(data->rclass);
|
166
|
+
rb_gc_mark(data->oclass);
|
167
|
+
rb_gc_mark(data->recv);
|
168
|
+
rb_gc_mark((VALUE)data->body);
|
169
|
+
#endif
|
170
|
+
|
171
|
+
}
|
172
|
+
|
173
|
+
static VALUE
|
174
|
+
umethod_unchecked_bind(VALUE method, VALUE recv)
|
175
|
+
{
|
176
|
+
struct METHOD *data, *bound;
|
177
|
+
|
178
|
+
Data_Get_Struct(method, struct METHOD, data);
|
179
|
+
|
180
|
+
method = Data_Make_Struct(rb_cMethod, struct METHOD, bm_mark, -1, bound);
|
181
|
+
*bound = *data;
|
182
|
+
bound->recv = recv;
|
183
|
+
#ifdef RUBY1_8
|
184
|
+
bound->rklass = CLASS_OF(recv);
|
185
|
+
#endif
|
186
|
+
#ifdef RUBY1_9
|
187
|
+
bound->rclass = CLASS_OF(recv);
|
188
|
+
#endif
|
189
|
+
|
190
|
+
return method;
|
191
|
+
}
|
192
|
+
|
193
|
+
|
194
|
+
void Init_getsource_base() {
|
195
|
+
rb_define_method(rb_cMethod, "body", rb_method_body,0);
|
196
|
+
rb_define_method(rb_cUnboundMethod, "body", rb_method_body,0);
|
197
|
+
rb_define_method(rb_cUnboundMethod, "unchecked_bind", umethod_unchecked_bind,1);
|
198
|
+
|
199
|
+
/*
|
200
|
+
The class Node represents the internal ruby node, a node is a piece of ruby code used
|
201
|
+
for represent ruby methods in memory and other executable entities, many nodes come from
|
202
|
+
the ruby source code and may be associated with a file and line where thats node are defined
|
203
|
+
*/
|
204
|
+
rb_cNode = rb_define_class("Node", rb_cObject);
|
205
|
+
|
206
|
+
rb_define_method(rb_cNode, "line", rb_node_line, 0);
|
207
|
+
rb_define_method(rb_cNode, "file", rb_node_file, 0);
|
208
|
+
|
209
|
+
intern_owner = rb_intern("owner");
|
210
|
+
intern_name = rb_intern("name");
|
211
|
+
intern_sym = rb_intern("to_sym");
|
212
|
+
}
|
data/lib/getsource.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the getsource project, http://github.com/tario/getsource
|
4
|
+
|
5
|
+
Copyright (c) 2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
getsource is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
getsource is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with getsource. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "getsource_base"
|
22
|
+
|
23
|
+
class Object
|
24
|
+
def specific_method(arg1, arg2=nil)
|
25
|
+
if arg2
|
26
|
+
method_name = arg2
|
27
|
+
klass = arg1
|
28
|
+
|
29
|
+
if instance_of? Class
|
30
|
+
method(method_name)
|
31
|
+
else
|
32
|
+
klass.instance_method(method_name).bind(self)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
method(arg1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: getsource
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dario Seminara
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-30 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email: robertodarioseminara@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions:
|
27
|
+
- ext/getsource_base/extconf.rb
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README
|
30
|
+
files:
|
31
|
+
- examples/test1/source1.rb
|
32
|
+
- examples/test1/main.rb
|
33
|
+
- examples/test1/source2.rb
|
34
|
+
- lib/getsource.rb
|
35
|
+
- ext/getsource_base/getsource_base.c
|
36
|
+
- ext/getsource_base/extconf.rb
|
37
|
+
- AUTHORS
|
38
|
+
- CHANGELOG
|
39
|
+
- README
|
40
|
+
- Rakefile
|
41
|
+
- TODO
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/tario/getsource
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options:
|
48
|
+
- --main
|
49
|
+
- README
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
hash: 3
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.7
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Get the source file path of the implementation of a given method
|
77
|
+
test_files: []
|
78
|
+
|