getsource 0.1.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/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
|
+
|