detective 0.1.0 → 0.2.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/README.rdoc +24 -2
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/detective.gemspec +3 -3
- data/lib/detective.rb +81 -58
- data/test/test_detective.rb +22 -7
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -14,7 +14,8 @@ View the source of a class method ...
|
|
14
14
|
require 'detective'
|
15
15
|
|
16
16
|
Detective.view_source('ActiveRecord::Base.find_by_sql')
|
17
|
-
|
17
|
+
|
18
|
+
Result
|
18
19
|
def find_by_sql(sql)
|
19
20
|
connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
|
20
21
|
end
|
@@ -23,6 +24,7 @@ View the source of an instance method ...
|
|
23
24
|
|
24
25
|
Detective.view_source('ActiveRecord::Base#update_attributes')
|
25
26
|
|
27
|
+
Result
|
26
28
|
def update_attributes(attributes)
|
27
29
|
self.attributes = attributes
|
28
30
|
save
|
@@ -39,6 +41,7 @@ View the source of an overrided method ...
|
|
39
41
|
|
40
42
|
Detective.view_source('ActiveRecord::Base#update_attributes')
|
41
43
|
|
44
|
+
Result
|
42
45
|
def update_attributes(attributes)
|
43
46
|
puts "updating attributes ..."
|
44
47
|
self.attributes = attributes
|
@@ -48,13 +51,32 @@ View the source of an overrided method ...
|
|
48
51
|
Find the location of some source ...
|
49
52
|
Detective.get_location('ActiveRecord::Base#attributes')
|
50
53
|
|
54
|
+
Result
|
51
55
|
location
|
52
56
|
/home/aseldawy/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb
|
53
57
|
2752
|
54
58
|
|
59
|
+
(new) You can also find source code for modules ...
|
60
|
+
Detective.view_source('AuthenticatedSystem#current_user')
|
61
|
+
|
62
|
+
Result
|
63
|
+
def current_user
|
64
|
+
@current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_user == false
|
65
|
+
end
|
66
|
+
|
67
|
+
(new) You have an alternative output ...
|
68
|
+
Detective.view_source('AuthenticatedSystem#current_user', :rdoc)
|
69
|
+
|
70
|
+
Result
|
71
|
+
/home/aseldawy/aptana_studio/archiving_system/lib/authenticated_system.rb, line 11
|
72
|
+
11: def current_user
|
73
|
+
12: @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_user == false
|
74
|
+
13: end
|
75
|
+
|
55
76
|
No luck with native methods ...
|
56
77
|
Detective.view_source('String#length')
|
57
|
-
|
78
|
+
|
79
|
+
Result
|
58
80
|
native method
|
59
81
|
|
60
82
|
== How it works (advanced)
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ begin
|
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "detective"
|
8
8
|
gem.summary = "Find source code of ruby methods"
|
9
|
-
gem.description = "A gem that allows you to view the source code of a method"
|
9
|
+
gem.description = "A ruby gem built by BadrIT (http://www.badrit.com/) that allows you to view the source code of a method"
|
10
10
|
gem.email = "ahmed.eldawy@badrit.com"
|
11
11
|
gem.homepage = "http://github.com/aseldawy/detective"
|
12
12
|
gem.authors = ["Ahmed ElDawy"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/detective.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{detective}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ahmed ElDawy"]
|
12
|
-
s.date = %q{2009-11-
|
13
|
-
s.description = %q{A gem that allows you to view the source code of a method}
|
12
|
+
s.date = %q{2009-11-21}
|
13
|
+
s.description = %q{A ruby gem built by BadrIT (http://www.badrit.com/) that allows you to view the source code of a method}
|
14
14
|
s.email = %q{ahmed.eldawy@badrit.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
data/lib/detective.rb
CHANGED
@@ -2,9 +2,14 @@ require 'ruby_parser'
|
|
2
2
|
|
3
3
|
module Detective
|
4
4
|
|
5
|
-
|
5
|
+
begin
|
6
|
+
fork {exit!}
|
7
|
+
ForkSupported = true
|
8
|
+
rescue Exception
|
9
|
+
ForkSupported = false
|
10
|
+
end
|
6
11
|
|
7
|
-
def self.view_source(method)
|
12
|
+
def self.view_source(method, format=:plain)
|
8
13
|
location = get_location(method).strip.split /[\r\n]+/
|
9
14
|
case location.first
|
10
15
|
when 'native method' then return 'native method'
|
@@ -15,19 +20,29 @@ module Detective
|
|
15
20
|
line_no = line_no.to_i
|
16
21
|
f = File.open filename
|
17
22
|
source = ""
|
18
|
-
|
23
|
+
output = case format
|
24
|
+
when :plain then ""
|
25
|
+
when :rdoc then "#{filename}, line #{line_no}" << "\r\n"
|
26
|
+
else ""
|
27
|
+
end
|
28
|
+
current_line_no = 0
|
19
29
|
rp = RubyParser.new
|
20
|
-
f.each_line do |
|
21
|
-
|
22
|
-
if
|
23
|
-
|
30
|
+
f.each_line do |current_line|
|
31
|
+
current_line_no += 1
|
32
|
+
if current_line_no >= line_no
|
33
|
+
output << case format
|
34
|
+
when :plain then current_line
|
35
|
+
when :rdoc then "#{current_line_no}:#{current_line}"
|
36
|
+
else current_line
|
37
|
+
end
|
38
|
+
source << current_line
|
24
39
|
# Try to parse it to know whether the method is complete or not
|
25
40
|
rp.parse(source) && break rescue nil
|
26
41
|
end
|
27
42
|
end
|
28
43
|
f.close
|
29
|
-
return
|
30
|
-
rescue
|
44
|
+
return output
|
45
|
+
rescue Exception => e
|
31
46
|
return "Cannot find source code"
|
32
47
|
end
|
33
48
|
end
|
@@ -62,31 +77,31 @@ private
|
|
62
77
|
end
|
63
78
|
result = ""
|
64
79
|
t = Thread.new do
|
65
|
-
# child process
|
66
|
-
detective_state = 0
|
67
|
-
# Get an instance of class Method that can be invoked using Method#call
|
68
|
-
the_method, args = get_method(the_klass, method_name, class_method)
|
69
|
-
set_trace_func(proc do |event, file, line, id, binding, classname|
|
70
|
-
if id == :call
|
71
|
-
detective_state = 1
|
72
|
-
return
|
73
|
-
end
|
74
|
-
return if detective_state == 0
|
75
|
-
if event == 'call'
|
76
|
-
result << "location" << "\r\n"
|
77
|
-
result << file << "\r\n"
|
78
|
-
result << line.to_s << "\r\n"
|
79
|
-
# Cancel debugging
|
80
|
-
set_trace_func nil
|
81
|
-
Thread.kill(Thread.current)
|
82
|
-
elsif event == 'c-call'
|
83
|
-
result << 'native method'
|
84
|
-
set_trace_func nil
|
85
|
-
Thread.kill(Thread.current)
|
86
|
-
end
|
87
|
-
end)
|
88
|
-
|
89
80
|
begin
|
81
|
+
# child process
|
82
|
+
detective_state = 0
|
83
|
+
# Get an instance of class Method that can be invoked using Method#call
|
84
|
+
the_method, args = get_method(the_klass, method_name, class_method)
|
85
|
+
set_trace_func(proc do |event, file, line, id, binding, classname|
|
86
|
+
if id == :call
|
87
|
+
detective_state = 1
|
88
|
+
return
|
89
|
+
end
|
90
|
+
return if detective_state == 0
|
91
|
+
if event == 'call'
|
92
|
+
result << "location" << "\r\n"
|
93
|
+
result << file << "\r\n"
|
94
|
+
result << line.to_s << "\r\n"
|
95
|
+
# Cancel debugging
|
96
|
+
set_trace_func nil
|
97
|
+
Thread.kill(Thread.current)
|
98
|
+
elsif event == 'c-call'
|
99
|
+
result << 'native method'
|
100
|
+
set_trace_func nil
|
101
|
+
Thread.kill(Thread.current)
|
102
|
+
end
|
103
|
+
end)
|
104
|
+
|
90
105
|
the_method.call *args
|
91
106
|
# If the next line executed, this indicates an error because the method should be cancelled before called
|
92
107
|
result << "method called!" << "\r\n"
|
@@ -102,30 +117,30 @@ private
|
|
102
117
|
def self.get_location_fork(the_klass, method_name, class_method)
|
103
118
|
f = open("|-", "w+")
|
104
119
|
if f == nil
|
105
|
-
# child process
|
106
|
-
detective_state = 0
|
107
|
-
# Get an instance of class Method that can be invoked using Method#call
|
108
|
-
the_method, args = get_method(the_klass, method_name, class_method)
|
109
|
-
set_trace_func(proc do |event, file, line, id, binding, classname|
|
110
|
-
if id == :call
|
111
|
-
detective_state = 1
|
112
|
-
return
|
113
|
-
end
|
114
|
-
return if detective_state == 0
|
115
|
-
if event == 'call'
|
116
|
-
puts "location"
|
117
|
-
puts file
|
118
|
-
puts line
|
119
|
-
set_trace_func nil
|
120
|
-
exit!
|
121
|
-
elsif event == 'c-call'
|
122
|
-
puts 'native method'
|
123
|
-
set_trace_func nil
|
124
|
-
exit!
|
125
|
-
end
|
126
|
-
end)
|
127
|
-
|
128
120
|
begin
|
121
|
+
# child process
|
122
|
+
detective_state = 0
|
123
|
+
# Get an instance of class Method that can be invoked using Method#call
|
124
|
+
the_method, args = get_method(the_klass, method_name, class_method)
|
125
|
+
set_trace_func(proc do |event, file, line, id, binding, classname|
|
126
|
+
if id == :call
|
127
|
+
detective_state = 1
|
128
|
+
return
|
129
|
+
end
|
130
|
+
return if detective_state == 0
|
131
|
+
if event == 'call'
|
132
|
+
puts "location"
|
133
|
+
puts file
|
134
|
+
puts line
|
135
|
+
set_trace_func nil
|
136
|
+
exit!
|
137
|
+
elsif event == 'c-call'
|
138
|
+
puts 'native method'
|
139
|
+
set_trace_func nil
|
140
|
+
exit!
|
141
|
+
end
|
142
|
+
end)
|
143
|
+
|
129
144
|
the_method.call *args
|
130
145
|
# If the next line executed, this indicates an error because the method should be cancelled before called
|
131
146
|
puts "method called!"
|
@@ -146,8 +161,11 @@ private
|
|
146
161
|
def self.get_method(the_klass, method_name, class_method)
|
147
162
|
if class_method
|
148
163
|
the_method = the_klass.method(method_name)
|
149
|
-
|
150
|
-
# Create
|
164
|
+
elsif the_klass.is_a? Class
|
165
|
+
# Create an instance of the given class
|
166
|
+
# Create a new empty initialize method to bypass initialization ...
|
167
|
+
# because some classes require special attributes when created.
|
168
|
+
# Some other like ActiveRecord::Base does not allow to be instantiated at all
|
151
169
|
the_klass.class_eval do
|
152
170
|
alias old_initialize initialize
|
153
171
|
def initialize
|
@@ -161,6 +179,11 @@ private
|
|
161
179
|
# undef initialize
|
162
180
|
alias initialize old_initialize
|
163
181
|
end
|
182
|
+
elsif the_klass.is_a? Module
|
183
|
+
# Crate any object and let it extends the given module
|
184
|
+
object = Object.new
|
185
|
+
object.extend the_klass
|
186
|
+
the_method = object.method(method_name)
|
164
187
|
end
|
165
188
|
# check how many attributes are required
|
166
189
|
the_method_arity = the_method.arity
|
data/test/test_detective.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
class BadrIT
|
3
|
+
class BadrIT
|
4
|
+
def self.hello
|
5
|
+
puts "hello BadrIT"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
module IPhone; end
|
9
|
+
|
4
10
|
|
5
11
|
class TestDetective < Test::Unit::TestCase
|
6
12
|
def test_simple_method
|
7
|
-
BadrIT.class_eval do
|
8
|
-
def self.hello
|
9
|
-
puts "hello BadrIT"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
13
|
source = Detective.view_source('BadrIT.hello')
|
14
14
|
assert_equal 'def self.hello puts "hello BadrIT" end', source.gsub(/\s+/, ' ').strip
|
15
15
|
end
|
@@ -137,5 +137,20 @@ class TestDetective < Test::Unit::TestCase
|
|
137
137
|
Detective.view_source('BadrIT')
|
138
138
|
end
|
139
139
|
end
|
140
|
+
|
141
|
+
def test_moudle_source
|
142
|
+
IPhone.module_eval do
|
143
|
+
def app_store
|
144
|
+
puts "app_store!"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
source = Detective.view_source('IPhone#app_store')
|
149
|
+
assert_equal 'def app_store puts "app_store!" end', source.gsub(/\s+/, ' ').strip
|
150
|
+
end
|
140
151
|
|
152
|
+
def test_rdoc_format
|
153
|
+
source = Detective.view_source('BadrIT.hello', :rdoc)
|
154
|
+
assert_equal "#{__FILE__}, line 4 4: def self.hello 5: puts \"hello BadrIT\" 6: end", source.gsub(/\s+/, ' ').strip
|
155
|
+
end
|
141
156
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: detective
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ahmed ElDawy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-21 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
-
description: A gem that allows you to view the source code of a method
|
25
|
+
description: A ruby gem built by BadrIT (http://www.badrit.com/) that allows you to view the source code of a method
|
26
26
|
email: ahmed.eldawy@badrit.com
|
27
27
|
executables: []
|
28
28
|
|