is_a 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -5
- data/Rakefile +20 -64
- data/ext/is_a/is_a.c +25 -7
- data/is_a.gemspec +1 -0
- data/lib/is_a/version.rb +1 -1
- data/spec/is_a_spec.rb +51 -0
- metadata +23 -5
data/README.md
CHANGED
@@ -6,7 +6,9 @@ A small library of missing ruby methods for introspection. See Usage.
|
|
6
6
|
|
7
7
|
Add this line to your application's Gemfile:
|
8
8
|
|
9
|
-
|
9
|
+
```ruby
|
10
|
+
gem 'is_a'
|
11
|
+
```
|
10
12
|
|
11
13
|
And then execute:
|
12
14
|
|
@@ -42,7 +44,7 @@ ObjectSpace._id2ref(id) == obj # => true
|
|
42
44
|
#For 1.9.3 use BasicObject#__id__
|
43
45
|
```
|
44
46
|
|
45
|
-
### Fast
|
47
|
+
### Fast single line from caller
|
46
48
|
|
47
49
|
Ruby's `caller` is handy, but sometimes you do not need the whole array of strings it allocates generates on each call.
|
48
50
|
|
@@ -61,9 +63,9 @@ end
|
|
61
63
|
Results:
|
62
64
|
|
63
65
|
```
|
64
|
-
|
65
|
-
caller[1]
|
66
|
-
caller_line
|
66
|
+
user system total real
|
67
|
+
caller[1] 1.760000 0.040000 1.800000 ( 1.802799)
|
68
|
+
caller_line 0.080000 0.000000 0.080000 ( 0.089649)
|
67
69
|
```
|
68
70
|
|
69
71
|
|
data/Rakefile
CHANGED
@@ -4,77 +4,33 @@ require "bundler/gem_tasks"
|
|
4
4
|
require 'rake/extensiontask'
|
5
5
|
Rake::ExtensionTask.new('is_a')
|
6
6
|
|
7
|
-
|
8
|
-
task :test => :compile do
|
7
|
+
require 'rake/testtask'
|
9
8
|
|
10
|
-
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.pattern = 'spec/**/*_spec.rb'
|
11
|
+
t.libs.push 'spec'
|
12
|
+
end
|
11
13
|
|
12
|
-
require "bundler/setup"
|
13
|
-
require 'is_a'
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
@search_me = 12345
|
18
|
-
end
|
19
|
-
def lala
|
20
|
-
end
|
21
|
-
end
|
15
|
+
desc "Simple dump test,just to check if extension compiles and does not segfault on simple dump"
|
16
|
+
task :test => :compile
|
22
17
|
|
23
|
-
|
18
|
+
task :default => :test
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
desc "Make simple benchmark for caller_line"
|
21
|
+
task :bench_caller_line do
|
22
|
+
require 'bundler/setup'
|
23
|
+
require 'is_a'
|
24
|
+
require 'benchmark'
|
25
|
+
n = 50000
|
26
|
+
class UtilClassWithCallerline
|
27
|
+
class << self
|
28
|
+
define_method :caller_line, method(:caller_line)
|
31
29
|
end
|
32
|
-
|
33
|
-
puts "Cls is #{cls1.inspect}, #{classes.inspect}"
|
34
|
-
cls1
|
35
|
-
end
|
36
|
-
|
37
|
-
c = cls obj
|
38
|
-
cls c
|
39
|
-
cls nil
|
40
|
-
|
41
|
-
id = IsA.id_of(obj)
|
42
|
-
puts "Id is #{id}"
|
43
|
-
if ObjectSpace._id2ref(id) == obj
|
44
|
-
puts "Getref ok"
|
45
|
-
else
|
46
|
-
puts "Getref FAIL"
|
47
30
|
end
|
48
|
-
|
49
|
-
unless IsA.object?(obj)
|
50
|
-
puts "object? ok"
|
51
|
-
else
|
52
|
-
puts "object? FAIL"
|
53
|
-
end
|
54
|
-
|
55
|
-
if IsA.object?(c)
|
56
|
-
puts "object? ok"
|
57
|
-
else
|
58
|
-
puts "object? FAIL"
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_caller
|
62
|
-
puts "Real caller: #{caller[0]}"
|
63
|
-
puts "Caller at 0: #{IsA.caller_line(0)}"
|
64
|
-
puts caller_line
|
65
|
-
end
|
66
|
-
|
67
|
-
test_caller
|
68
|
-
|
69
|
-
require 'benchmark'
|
70
|
-
n = 10000
|
71
|
-
Benchmark.bm(11) do |x|
|
31
|
+
Benchmark.bm(19) do |x|
|
72
32
|
x.report("caller[1]") { n.times { caller[1] } }
|
73
33
|
x.report("caller_line") { n.times { caller_line(1) } }
|
34
|
+
x.report("caller_line in ctx") { n.times { UtilClassWithCallerline.caller_line(1) } }
|
74
35
|
end
|
75
|
-
|
76
|
-
#require 'heap_dump'
|
77
|
-
#HeapDump.dump
|
78
|
-
end
|
79
|
-
|
80
|
-
task :default => :test
|
36
|
+
end
|
data/ext/is_a/is_a.c
CHANGED
@@ -35,13 +35,17 @@ static VALUE caller_line(int offset)
|
|
35
35
|
rb_control_frame_t* cfp = th->cfp + offset;
|
36
36
|
const rb_control_frame_t* stack_end = (void *)(th->stack + th->stack_size);
|
37
37
|
|
38
|
-
|
38
|
+
VALUE name = 0;
|
39
|
+
|
40
|
+
while(cfp < stack_end){
|
39
41
|
if (cfp->iseq != 0) {
|
40
42
|
if (cfp->pc != 0) {
|
41
43
|
rb_iseq_t *iseq = cfp->iseq;
|
42
44
|
int line_no = rb_vm_get_sourceline(cfp);
|
43
|
-
VALUE file = iseq->filename
|
44
|
-
|
45
|
+
VALUE file = iseq->filename;
|
46
|
+
//name may be passed from previous iteration
|
47
|
+
if(!name)
|
48
|
+
name = iseq->name;
|
45
49
|
if (line_no) {
|
46
50
|
return rb_enc_sprintf(
|
47
51
|
rb_enc_compatible(file, name),
|
@@ -55,12 +59,26 @@ static VALUE caller_line(int offset)
|
|
55
59
|
}
|
56
60
|
}
|
57
61
|
} else {
|
58
|
-
//
|
59
|
-
|
62
|
+
// for CFUNCs - search for previous ruby frame for location
|
63
|
+
if (RUBYVM_CFUNC_FRAME_P(cfp)) {
|
64
|
+
if (!name){
|
65
|
+
ID id;
|
66
|
+
if (cfp->me->def)
|
67
|
+
id = cfp->me->def->original_id;
|
68
|
+
else
|
69
|
+
id = cfp->me->called_id;
|
70
|
+
if (id != ID_ALLOCATOR){
|
71
|
+
name = rb_id2str(id);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
cfp += 1;
|
76
|
+
continue;
|
60
77
|
}
|
61
|
-
|
62
|
-
// level is out of bounds
|
78
|
+
break;
|
63
79
|
}
|
80
|
+
|
81
|
+
// level is out of bounds
|
64
82
|
return Qnil;
|
65
83
|
}
|
66
84
|
|
data/is_a.gemspec
CHANGED
data/lib/is_a/version.rb
CHANGED
data/spec/is_a_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'is_a'
|
4
|
+
|
5
|
+
describe IsA do
|
6
|
+
|
7
|
+
subject { IsA }
|
8
|
+
|
9
|
+
it 'id_of' do
|
10
|
+
obj = Class.new(BasicObject){}.new
|
11
|
+
|
12
|
+
id = subject.id_of(obj)
|
13
|
+
assert_equal(obj, ObjectSpace._id2ref(id))
|
14
|
+
end
|
15
|
+
|
16
|
+
it "object?" do
|
17
|
+
subject.object?(Class.new(BasicObject){}.new).must_equal false
|
18
|
+
subject.object?("string is object").must_equal true
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "caller_line" do
|
22
|
+
it "in methods" do
|
23
|
+
def test_caller
|
24
|
+
[caller[0], subject.caller_line(0)]
|
25
|
+
end
|
26
|
+
r = test_caller
|
27
|
+
r.first.must_equal r.last
|
28
|
+
end
|
29
|
+
|
30
|
+
it "in blocks" do
|
31
|
+
r = proc{
|
32
|
+
[caller[0], subject.caller_line(0)]
|
33
|
+
}.call
|
34
|
+
r.last.wont_be_nil
|
35
|
+
r.first.must_equal r.last
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be faster than caller[0]" do
|
39
|
+
n = 1000
|
40
|
+
anchor = Benchmark.measure{ n.times{ caller[0] } }
|
41
|
+
res = Benchmark.measure{ n.times{ subject.caller_line(0) } }
|
42
|
+
assert_operator res.total, :<, anchor.total
|
43
|
+
assert_operator res.real, :<, anchor.real
|
44
|
+
assert_operator res.utime, :<, anchor.utime
|
45
|
+
|
46
|
+
# no large memory allocation => no system cpu time
|
47
|
+
res.stime.must_equal 0.0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: is_a
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debugger-ruby_core_source
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: minitest
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
description: Fear weak references to BasicObject no more
|
47
63
|
email:
|
48
64
|
- vasilyfedoseyev@gmail.com
|
@@ -61,6 +77,7 @@ files:
|
|
61
77
|
- is_a.gemspec
|
62
78
|
- lib/is_a.rb
|
63
79
|
- lib/is_a/version.rb
|
80
|
+
- spec/is_a_spec.rb
|
64
81
|
homepage: http://github.com/Vasfed/is_a
|
65
82
|
licenses: []
|
66
83
|
post_install_message:
|
@@ -75,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
92
|
version: '0'
|
76
93
|
segments:
|
77
94
|
- 0
|
78
|
-
hash:
|
95
|
+
hash: 2510194417071522637
|
79
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
97
|
none: false
|
81
98
|
requirements:
|
@@ -84,11 +101,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
101
|
version: '0'
|
85
102
|
segments:
|
86
103
|
- 0
|
87
|
-
hash:
|
104
|
+
hash: 2510194417071522637
|
88
105
|
requirements: []
|
89
106
|
rubyforge_project:
|
90
107
|
rubygems_version: 1.8.24
|
91
108
|
signing_key:
|
92
109
|
specification_version: 3
|
93
110
|
summary: Defines methods to introspect any ruby object more deeply
|
94
|
-
test_files:
|
111
|
+
test_files:
|
112
|
+
- spec/is_a_spec.rb
|