is_a 0.0.3 → 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/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:
|