class ADSL::Extract::Instrumenter
Attributes
instrumentation_filters[RW]
method_locals_stack[R]
stack_depth[R]
Public Class Methods
get_instance()
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 25 def self.get_instance() @instance end
instrumented()
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 33 def self.instrumented() # a dummy method injected into the AST end
new(instrument_domain = Dir.pwd)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 84 def initialize(instrument_domain = Dir.pwd) @instrument_domain = instrument_domain @replacers = [] @stack_depth = 0 @method_locals_stack = [] # mark the instrumentation replace :defn, :defs do |sexp| mark_sexp_instrumented sexp end # make sure the instrumentation propagates through calls replace :call do |sexp| # expected format: s(:call, object, method_name, *args) # replaced with Extract::Instrumenter.e(instrumenter_id, object, method_name, *args) original_object = sexp.sexp_body[0] || s(:self) original_method_name = sexp.sexp_body[1] original_args = sexp.sexp_body[2..-1] next sexp if [s(:self), nil].include? original_object and Kernel.respond_to? original_method_name s(:call, nil, :ins_call, original_object, s(:lit, original_method_name), *original_args) end end
Public Instance Methods
convert_root_defs_into_defn(sexp)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 152 def convert_root_defs_into_defn(sexp) sexp.sexp_type == :defs ? s(:defn, *sexp[2..-1]) : sexp end
exec_within() { |self| ... }
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 49 def exec_within Instrumenter.instance_variable_set(:@instance, self) if @stack_depth == 0 @stack_depth += 1 @method_locals_stack << create_locals if respond_to? :create_locals return yield(self) ensure @stack_depth -= 1 @method_locals_stack.pop Instrumenter.instance_variable_set(:@instance, nil) if @stack_depth == 0 end
execute_instrumented(object, method_name, *args, &block)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 145 def execute_instrumented(object, method_name, *args, &block) self.exec_within do instrument object, method_name return object.send method_name, *args, &block end end
instrument(object, method_name)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 166 def instrument(object, method_name) if should_instrument? object, method_name begin # this is complex because I want to avoid using .method on non-class objects # because they might implement method themselves method = object.singleton_class.instance_method method_name source = method.source # Ruby 2.0.0 support is in development as of writing this sexp = ruby_parser.process source unless sexp.nil? sexp = convert_root_defs_into_defn sexp instrumented_sexp = instrument_sexp sexp new_code = Ruby2Ruby.new.process instrumented_sexp object.replace_method method_name, new_code new_code else source end rescue MethodSource::SourceNotFoundError end end end
instrument_sexp(sexp)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 196 def instrument_sexp(sexp) return nil if sexp.nil? @replacers.reverse_each do |types, block, options| sexp = sexp.block_replace *types, options, &block end sexp end
instrument_string(source)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 156 def instrument_string(source) sexp = ruby_parser.process source unless sexp.nil? instrumented_sexp = instrument_sexp sexp new_code = Ruby2Ruby.new.process instrumented_sexp else source end end
mark_sexp_instrumented(sexp)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 61 def mark_sexp_instrumented(sexp) raise 'Already instrumented' if sexp_instrumented? sexp first_stmt = sexp[3] if first_stmt[0] != :call or first_stmt[1] != Instrumenter.to_sexp or first_stmt[2] != :instrumented new_stmt = s(:call, Instrumenter.to_sexp, :instrumented) sexp.insert 3, new_stmt end sexp end
method_locals()
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 37 def method_locals @method_locals_stack.last end
previous_locals()
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 41 def previous_locals @method_locals_stack[-2] end
replace(*types, &block)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 133 def replace(*types, &block) options = types.last.is_a?(Hash) ? types.pop : {} @replacers << [types, block, options] end
root_locals()
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 45 def root_locals @method_locals_stack.first end
ruby_parser()
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 29 def ruby_parser RUBY_VERSION >= '2' ? Ruby19Parser.new : RubyParser.for_current_ruby end
sexp_instrumented?(sexp)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 75 def sexp_instrumented?(sexp) first_stmt = sexp[3] return (first_stmt[0] == :call and first_stmt[1] == Instrumenter.to_sexp and first_stmt[2] == :instrumented) rescue MethodSource::SourceNotFoundError return end
should_instrument?(object, method_name)
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 109 def should_instrument?(object, method_name) return false if object.is_a?(Fixnum) or object.is_a?(Symbol) method = object.singleton_class.instance_method method_name return false if method.source_location.nil? return false if method.owner == Kernel return false if @instrument_domain && !(method.source_location.first =~ /^#{@instrument_domain}.*$/) (instrumentation_filters || []).each do |filter| return false unless filter.allow_instrumentation? object, method_name end source = method.source sexp = ruby_parser.process source !sexp_instrumented? sexp rescue MethodSource::SourceNotFoundError # sometimes this happens because the method_source gem bugs out with evals etc return false rescue NameError => e # ghost method with no available source return false end
with_replace(*types, replacer) { || ... }
click to toggle source
# File lib/adsl/extract/instrumenter.rb, line 138 def with_replace(*types, replacer) replace *types, replacer yield ensure @replacers.pop end