is_a 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +28 -0
- data/Rakefile +14 -0
- data/ext/is_a/extconf.rb +31 -1
- data/ext/is_a/is_a.c +74 -0
- data/is_a.gemspec +1 -0
- data/lib/is_a/version.rb +1 -1
- metadata +32 -6
data/README.md
CHANGED
@@ -18,6 +18,9 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
### BasicObject
|
22
|
+
If you got an object via `_id2ref` or from similar place - do not rush to duck-typing, it may be a BasicObject and not respond to `respond_to?`. IsA aims in handling such cases.
|
23
|
+
|
21
24
|
```ruby
|
22
25
|
require 'is_a'
|
23
26
|
|
@@ -39,6 +42,31 @@ ObjectSpace._id2ref(id) == obj # => true
|
|
39
42
|
#For 1.9.3 use BasicObject#__id__
|
40
43
|
```
|
41
44
|
|
45
|
+
### Fast getting of lines from caller
|
46
|
+
|
47
|
+
Ruby's `caller` is handy, but sometimes you do not need the whole array of strings it allocates generates on each call.
|
48
|
+
|
49
|
+
`IsA.caller_line` (also global `caller_line`) is a lot faster and does not mess your heap that lot (allocates just the result string, meaning fewer GC):
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require 'is_a'
|
53
|
+
require 'benchmark'
|
54
|
+
n = 10000
|
55
|
+
Benchmark.bm(11) do |x|
|
56
|
+
x.report("caller[1]") { n.times { caller[1] } }
|
57
|
+
x.report("caller_line") { n.times { caller_line(1) } }
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
Results:
|
62
|
+
|
63
|
+
```
|
64
|
+
user system total real
|
65
|
+
caller[1] 0.430000 0.010000 0.440000 ( 0.443102)
|
66
|
+
caller_line 0.010000 0.000000 0.010000 ( 0.002275)
|
67
|
+
```
|
68
|
+
|
69
|
+
|
42
70
|
## Contributing
|
43
71
|
|
44
72
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -58,6 +58,20 @@ task :test => :compile do
|
|
58
58
|
puts "object? FAIL"
|
59
59
|
end
|
60
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|
|
72
|
+
x.report("caller[1]") { n.times { caller[1] } }
|
73
|
+
x.report("caller_line") { n.times { caller_line(1) } }
|
74
|
+
end
|
61
75
|
|
62
76
|
#require 'heap_dump'
|
63
77
|
#HeapDump.dump
|
data/ext/is_a/extconf.rb
CHANGED
@@ -1,3 +1,33 @@
|
|
1
1
|
require 'mkmf'
|
2
|
+
require 'debugger/ruby_core_source'
|
2
3
|
|
3
|
-
|
4
|
+
unless ARGV.any? {|arg| arg.include?('--with-ruby-include') }
|
5
|
+
require 'rbconfig'
|
6
|
+
bindir = RbConfig::CONFIG['bindir']
|
7
|
+
if bindir =~ %r{(^.*/\.rbenv/versions)/([^/]+)/bin$}
|
8
|
+
ruby_include = "#{$1}/#{$2}/include/ruby-1.9.1/ruby-#{$2}"
|
9
|
+
ARGV << "--with-ruby-include=#{ruby_include}"
|
10
|
+
elsif bindir =~ %r{(^.*/\.rvm/rubies)/([^/]+)/bin$}
|
11
|
+
ruby_include = "#{$1}/#{$2}/include/ruby-1.9.1/#{$2}"
|
12
|
+
ruby_include = "#{ENV['rvm_path']}/src/#{$2}" unless File.exist?(ruby_include)
|
13
|
+
ARGV << "--with-ruby-include=#{ruby_include}"
|
14
|
+
end
|
15
|
+
puts "Using ruby source from #{ruby_include}"
|
16
|
+
end
|
17
|
+
|
18
|
+
hdrs = ->{
|
19
|
+
res = %w{
|
20
|
+
vm_core.h
|
21
|
+
}.all?{|hdr| have_header(hdr)}
|
22
|
+
res
|
23
|
+
}
|
24
|
+
|
25
|
+
# create_makefile('is_a')
|
26
|
+
if !Debugger::RubyCoreSource::create_makefile_with_core(hdrs, "is_a")
|
27
|
+
STDERR.print("Makefile creation failed\n")
|
28
|
+
STDERR.print("*************************************************************\n\n")
|
29
|
+
STDERR.print(" NOTE: If your headers were not found, try passing\n")
|
30
|
+
STDERR.print(" --with-ruby-include=PATH_TO_HEADERS \n\n")
|
31
|
+
STDERR.print("*************************************************************\n\n")
|
32
|
+
exit(1)
|
33
|
+
end
|
data/ext/is_a/is_a.c
CHANGED
@@ -19,8 +19,82 @@ rb_object_id_of(VALUE self, VALUE obj)
|
|
19
19
|
return rb_obj_id(obj);
|
20
20
|
}
|
21
21
|
|
22
|
+
|
23
|
+
#ifdef HAVE_VM_CORE_H
|
24
|
+
#include "ruby/encoding.h"
|
25
|
+
#include "vm_core.h"
|
26
|
+
|
27
|
+
#define HAVE_CALLER_AT
|
28
|
+
static VALUE caller_line(int offset)
|
29
|
+
{
|
30
|
+
const rb_thread_t *th = ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()));
|
31
|
+
offset += 2;
|
32
|
+
if(offset < 0)
|
33
|
+
return Qnil;
|
34
|
+
|
35
|
+
rb_control_frame_t* cfp = th->cfp + offset;
|
36
|
+
const rb_control_frame_t* stack_end = (void *)(th->stack + th->stack_size);
|
37
|
+
|
38
|
+
if(cfp < stack_end){
|
39
|
+
if (cfp->iseq != 0) {
|
40
|
+
if (cfp->pc != 0) {
|
41
|
+
rb_iseq_t *iseq = cfp->iseq;
|
42
|
+
int line_no = rb_vm_get_sourceline(cfp);
|
43
|
+
VALUE file = iseq->filename,
|
44
|
+
name = iseq->name;
|
45
|
+
if (line_no) {
|
46
|
+
return rb_enc_sprintf(
|
47
|
+
rb_enc_compatible(file, name),
|
48
|
+
"%s:%d:in `%s'",
|
49
|
+
RSTRING_PTR(file), line_no, RSTRING_PTR(name));
|
50
|
+
} else {
|
51
|
+
return rb_enc_sprintf(
|
52
|
+
rb_enc_compatible(file, name),
|
53
|
+
"%s:in `%s'",
|
54
|
+
RSTRING_PTR(file), RSTRING_PTR(name));
|
55
|
+
}
|
56
|
+
}
|
57
|
+
} else {
|
58
|
+
// printf("CFUNC\n");
|
59
|
+
return Qnil;
|
60
|
+
}
|
61
|
+
} else {
|
62
|
+
// level is out of bounds
|
63
|
+
}
|
64
|
+
return Qnil;
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE
|
68
|
+
rb_caller_line(VALUE self, VALUE r_offset)
|
69
|
+
{
|
70
|
+
int offset = NUM2INT(r_offset); // we are not interested in self
|
71
|
+
return caller_line(offset);
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE rb_caller_line_global(int argc, VALUE* argv)
|
75
|
+
{
|
76
|
+
VALUE level;
|
77
|
+
int lev;
|
78
|
+
|
79
|
+
rb_scan_args(argc, argv, "01", &level);
|
80
|
+
|
81
|
+
if (NIL_P(level))
|
82
|
+
lev = 0;
|
83
|
+
else
|
84
|
+
lev = NUM2INT(level);
|
85
|
+
|
86
|
+
if (lev < 0)
|
87
|
+
rb_raise(rb_eArgError, "negative level (%d)", lev);
|
88
|
+
return caller_line(lev);
|
89
|
+
}
|
90
|
+
#endif
|
91
|
+
|
22
92
|
void Init_is_a(){
|
23
93
|
rb_mIsA = rb_define_module("IsA");
|
24
94
|
rb_define_singleton_method(rb_mIsA, "class_of", rb_get_class_of, 1);
|
25
95
|
rb_define_singleton_method(rb_mIsA, "id_of", rb_object_id_of, 1);
|
96
|
+
#ifdef HAVE_CALLER_AT
|
97
|
+
rb_define_singleton_method(rb_mIsA, "caller_line", rb_caller_line, 1);
|
98
|
+
rb_define_global_function("caller_line", rb_caller_line_global, -1);
|
99
|
+
#endif
|
26
100
|
}
|
data/is_a.gemspec
CHANGED
data/lib/is_a/version.rb
CHANGED
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,27 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: debugger-ruby_core_source
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rake-compiler
|
16
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
17
33
|
none: false
|
18
34
|
requirements:
|
19
35
|
- - ! '>='
|
@@ -21,7 +37,12 @@ dependencies:
|
|
21
37
|
version: '0'
|
22
38
|
type: :development
|
23
39
|
prerelease: false
|
24
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
25
46
|
description: Fear weak references to BasicObject no more
|
26
47
|
email:
|
27
48
|
- vasilyfedoseyev@gmail.com
|
@@ -52,17 +73,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
73
|
- - ! '>='
|
53
74
|
- !ruby/object:Gem::Version
|
54
75
|
version: '0'
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
hash: 3551024361612674054
|
55
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
80
|
none: false
|
57
81
|
requirements:
|
58
82
|
- - ! '>='
|
59
83
|
- !ruby/object:Gem::Version
|
60
84
|
version: '0'
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
hash: 3551024361612674054
|
61
88
|
requirements: []
|
62
89
|
rubyforge_project:
|
63
|
-
rubygems_version: 1.8.
|
90
|
+
rubygems_version: 1.8.24
|
64
91
|
signing_key:
|
65
92
|
specification_version: 3
|
66
93
|
summary: Defines methods to introspect any ruby object more deeply
|
67
94
|
test_files: []
|
68
|
-
has_rdoc:
|