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 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
@@ -1,3 +1,33 @@
1
1
  require 'mkmf'
2
+ require 'debugger/ruby_core_source'
2
3
 
3
- create_makefile('is_a')
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
@@ -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
  }
@@ -17,5 +17,6 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.extensions = "ext/is_a/extconf.rb"
19
19
 
20
+ gem.add_dependency("debugger-ruby_core_source")
20
21
  gem.add_development_dependency "rake-compiler"
21
22
  end
@@ -1,3 +1,3 @@
1
1
  module IsA
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  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.0.3
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: 2012-06-11 00:00:00.000000000Z
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: &70116595563300 !ruby/object:Gem::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: *70116595563300
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.15
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: