Class: LetItGo::MethodCall
- Inherits:
-
Object
- Object
- LetItGo::MethodCall
- Defined in:
- lib/let_it_go/method_call.rb
Overview
Wraps logic that require knowledge of the method call can parse original method call’s source and determine if a string literal was passed into the method.
Instance Attribute Summary collapse
-
#call_count ⇒ Object
Returns the value of attribute call_count.
-
#file_name ⇒ Object
Returns the value of attribute file_name.
-
#klass ⇒ Object
Returns the value of attribute klass.
-
#line_number ⇒ Object
Returns the value of attribute line_number.
-
#method_name ⇒ Object
Returns the value of attribute method_name.
-
#positions ⇒ Object
Returns the value of attribute positions.
Instance Method Summary collapse
-
#called_with_string_literal? ⇒ Boolean
Parses original method call location Determines if a string literal was used or not.
- #count ⇒ Object
-
#initialize(klass:, method_name:, kaller:, positions:) ⇒ MethodCall
constructor
A new instance of MethodCall.
-
#key ⇒ Object
Needs to be very low cost, cannot incur disk read.
- #line_to_s ⇒ Object
-
#method_array ⇒ Object
Loop through each line in the caller and see if the method we’re watching is being called This is needed due to the way TracePoint deals with inheritance.
- #optimizable? ⇒ Boolean
- #string_allocation_count ⇒ Object
- #zero? ⇒ Boolean
Constructor Details
#initialize(klass:, method_name:, kaller:, positions:) ⇒ MethodCall
Returns a new instance of MethodCall.
10 11 12 13 14 15 16 17 18 |
# File 'lib/let_it_go/method_call.rb', line 10 def initialize(klass: , method_name: , kaller:, positions: ) @klass = klass @method_name = method_name.to_s # Subclasses report method definition as caller.first via TracePoint @key = "Method: #{klass}##{method_name} [#{kaller.first(2).inspect}]" @caller_lines = kaller.first(2).map {|kaller_line| CallerLine.new(kaller_line) } @positions = positions @call_count = 0 end |
Instance Attribute Details
#call_count ⇒ Object
Returns the value of attribute call_count.
8 9 10 |
# File 'lib/let_it_go/method_call.rb', line 8 def call_count @call_count end |
#file_name ⇒ Object
Returns the value of attribute file_name.
8 9 10 |
# File 'lib/let_it_go/method_call.rb', line 8 def file_name @file_name end |
#klass ⇒ Object
Returns the value of attribute klass.
8 9 10 |
# File 'lib/let_it_go/method_call.rb', line 8 def klass @klass end |
#line_number ⇒ Object
Returns the value of attribute line_number.
8 9 10 |
# File 'lib/let_it_go/method_call.rb', line 8 def line_number @line_number end |
#method_name ⇒ Object
Returns the value of attribute method_name.
8 9 10 |
# File 'lib/let_it_go/method_call.rb', line 8 def method_name @method_name end |
#positions ⇒ Object
Returns the value of attribute positions.
8 9 10 |
# File 'lib/let_it_go/method_call.rb', line 8 def positions @positions end |
Instance Method Details
#called_with_string_literal? ⇒ Boolean
Parses original method call location Determines if a string literal was used or not
72 73 74 75 76 77 78 |
# File 'lib/let_it_go/method_call.rb', line 72 def called_with_string_literal? @string_allocation_count = 0 method_array.each do |m| positions.each {|position| @string_allocation_count += 1 if m.arg_types[position] == :string_literal } end !@string_allocation_count.zero? end |
#count ⇒ Object
20 21 22 |
# File 'lib/let_it_go/method_call.rb', line 20 def count call_count * string_allocation_count end |
#key ⇒ Object
Needs to be very low cost, cannot incur disk read
81 82 83 |
# File 'lib/let_it_go/method_call.rb', line 81 def key @key end |
#line_to_s ⇒ Object
58 59 60 |
# File 'lib/let_it_go/method_call.rb', line 58 def line_to_s @line_to_s ||= contents_from_file_line(file_name, line_number) end |
#method_array ⇒ Object
Loop through each line in the caller and see if the method we’re watching is being called This is needed due to the way TracePoint deals with inheritance
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/let_it_go/method_call.rb', line 30 def method_array @parser = nil @caller_lines.each do |kaller| code = Ripper.sexp(kaller.contents) code ||= Ripper.sexp(kaller.contents.sub(/^\W*(if|unless)/, ''.freeze)) # if and unless "block" statements aren't valid one line ruby code code ||= Ripper.sexp(kaller.contents.sub(/do \|.*\|$/, ''.freeze)) # remove trailing do |thing| to make valid code code ||= Ripper.sexp(kaller.contents.sub(/(and|or)\W*$/, ''.freeze))# trailing and || or code ||= Ripper.sexp(kaller.contents.sub(/:\W*$/, ''.freeze)) # multi line ternary statements code ||= Ripper.sexp(kaller.contents.sub(/(^\W*)|({ \|?.*\|?)}/, ''.freeze)) # multi line blocks using {} puts "LetItGoFailed parse (#{kaller.file_name}:#{kaller.line_number}: \n \033[0;31m"+ kaller.contents.strip + "\e[0m".freeze if ENV['LET_IT_GO_RECORD_FAILED_CODE'] && code.nil? && kaller.contents.match(/"|'/) parser = ::LetItGo::WTFParser.new(code, contents: kaller.contents) if parser.each_method.any? { |m| m.method_name == method_name } @line_number = kaller.line_number @file_name = kaller.file_name @parser = parser parser.each_method.each(&:arg_types) break else next end end @parser || [] end |
#optimizable? ⇒ Boolean
62 63 64 |
# File 'lib/let_it_go/method_call.rb', line 62 def optimizable? @optimizable ||= called_with_string_literal? end |
#string_allocation_count ⇒ Object
66 67 68 |
# File 'lib/let_it_go/method_call.rb', line 66 def string_allocation_count @string_allocation_count end |
#zero? ⇒ Boolean
24 25 26 |
# File 'lib/let_it_go/method_call.rb', line 24 def zero? count.zero? end |