is_a 0.1.0 → 0.1.1
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.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
|