Class: Peeky::MethodInfo
- Inherits:
-
Object
- Object
- Peeky::MethodInfo
- Extended by:
- Forwardable
- Defined in:
- lib/peeky/method_info.rb
Overview
Method info store a list of instance methods and attr_* for a ruby class.
Instance Attribute Summary collapse
-
#access_control ⇒ Object
readonly
Returns the value of attribute access_control.
-
#focal_method ⇒ Object
readonly
MethodInfo delegates to the underlying ruby method object.
-
#implementation_type ⇒ Object
readonly
Implementation type indicates the probable representation of this method in ruby, was it instance method ‘def method` instance method reader `attr_reader` instance method writer `attr_writer` class method `def self.method`.
-
#parameters ⇒ Object
List of parameters for this method.
Instance Method Summary collapse
-
#clean_name ⇒ Object
Name of method minus writer annotations Example :writable_attribute= # becomes :writable_attribute.
-
#get_parameter(name) ⇒ Object
Get parameter by name.
- #grab_source(limit = 10) ⇒ Object
-
#infer_default_paramaters ⇒ Object
Infer default paramater values.
-
#infer_implementation_type ⇒ Object
Infer implementation type [:class_method, :method, :attr_reader or :attr_writer].
-
#initialize(method, target_instance, implementation_type: :method, access_control: :public) ⇒ MethodInfo
constructor
A new instance of MethodInfo.
-
#match(predicate) ⇒ Object
Match.
-
#method? ⇒ Boolean
True when implementation type is method?.
-
#optional? ⇒ Boolean
True when any parameter is optional?.
-
#readable? ⇒ Boolean
Readable?.
- #tracer ⇒ Object
-
#writable? ⇒ Boolean
True when implementation_type writable?.
Constructor Details
#initialize(method, target_instance, implementation_type: :method, access_control: :public) ⇒ MethodInfo
Returns a new instance of MethodInfo.
32 33 34 35 36 37 38 39 40 41 |
# File 'lib/peeky/method_info.rb', line 32 def initialize(method, target_instance, implementation_type: :method, access_control: :public) @focal_method = method @target_instance = target_instance @access_control = access_control @implementation_type = implementation_type @parameters = ParameterInfo.from_method(method) infer_implementation_type infer_default_paramaters end |
Instance Attribute Details
#access_control ⇒ Object (readonly)
Returns the value of attribute access_control.
17 18 19 |
# File 'lib/peeky/method_info.rb', line 17 def access_control @access_control end |
#focal_method ⇒ Object (readonly)
MethodInfo delegates to the underlying ruby method object
15 16 17 |
# File 'lib/peeky/method_info.rb', line 15 def focal_method @focal_method end |
#implementation_type ⇒ Object (readonly)
Implementation type indicates the probable representation of this method in ruby, was it instance method ‘def method` instance method reader `attr_reader` instance method writer `attr_writer` class method `def self.method`
30 31 32 |
# File 'lib/peeky/method_info.rb', line 30 def implementation_type @implementation_type end |
#parameters ⇒ Object
List of parameters for this method
12 13 14 |
# File 'lib/peeky/method_info.rb', line 12 def parameters @parameters end |
Instance Method Details
#clean_name ⇒ Object
Name of method minus writer annotations Example
:writable_attribute=
# becomes
:writable_attribute
51 52 53 54 55 56 |
# File 'lib/peeky/method_info.rb', line 51 def clean_name @clean_name ||= begin n = name.to_s n.end_with?('=') ? n.delete_suffix('=').to_sym : name end end |
#get_parameter(name) ⇒ Object
Get parameter by name
69 70 71 72 |
# File 'lib/peeky/method_info.rb', line 69 def get_parameter(name) name = name.to_s parameters.find { |p| p.name == name } end |
#grab_source(limit = 10) ⇒ Object
170 171 172 173 |
# File 'lib/peeky/method_info.rb', line 170 def grab_source(limit = 10) file, line = @focal_method.source_location File.read(file).lines[line - 1, limit] if file && line end |
#infer_default_paramaters ⇒ Object
Infer default paramater values
WARNING: Unit test coverage went from .1 seconds to 30-40 seconds when I first introduced this method.
I now only call TracePoint if I have optional parameters to be inferred.
The tests are now down to 5 seconds, but it highlights the cost of use TracePoint.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/peeky/method_info.rb', line 90 def infer_default_paramaters class_name = @implementation_type == :class_method ? @target_instance.class.name : nil minimalist_method = Peeky::Renderer::MethodCallMinimumParamsRender.new(self, class_name: class_name).render return if minimalist_method.end_with?('=') return unless optional? # TODO: maybe I can use this technique instead and just read the source code # file, line = @focal_method.source_location tracer.enable do # puts grab_source # TODO: minimalist method should be able to handle class methods @target_instance.instance_eval(minimalist_method) if @implementation_type == :method @target_instance.class.instance_eval(minimalist_method) if @implementation_type == :class_method rescue StandardError, LoadError # => e # just print the error for now, we are only attempting to capture the # first call, any errors inside the call cannot be dealt with and should # not be re-raised # red full stop print "\e[31m.\e[0m" # puts minimalist_method # puts e.message end end |
#infer_implementation_type ⇒ Object
Infer implementation type [:class_method, :method, :attr_reader or :attr_writer]
59 60 61 62 63 64 |
# File 'lib/peeky/method_info.rb', line 59 def infer_implementation_type return unless @implementation_type == :method @implementation_type = :attr_reader if match(Peeky::Predicates::AttrReaderPredicate) @implementation_type = :attr_writer if match(Peeky::Predicates::AttrWriterPredicate) end |
#match(predicate) ⇒ Object
Match
135 136 137 |
# File 'lib/peeky/method_info.rb', line 135 def match(predicate) predicate.new.match(@target_instance, self) end |
#method? ⇒ Boolean
Returns true when implementation type is method?.
142 143 144 |
# File 'lib/peeky/method_info.rb', line 142 def method? @implementation_type == :method end |
#optional? ⇒ Boolean
Returns true when any parameter is optional?.
77 78 79 |
# File 'lib/peeky/method_info.rb', line 77 def optional? parameters.any?(&:optional?) end |
#readable? ⇒ Boolean
Readable?
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/peeky/method_info.rb', line 149 def readable? # Method naming issue: VSCode Ruby Language Server # # If this method is renamed to attr_readable, same for attr_writable. # # https://github.com/rubyide/vscode-ruby/issues/454 # if I prefix these methods with attr_ then will get an issue # in the language server. # # Cannot read property 'namedChildren' of undefined @implementation_type == :attr_reader end |
#tracer ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/peeky/method_info.rb', line 116 def tracer TracePoint.trace(:call, :c_call) do |tp| next unless tp.self.is_a?(@target_instance.class) next unless tp.method_id == name tp.parameters.each do |_type, param_name| method_paramater = get_parameter(param_name) if method_paramater.optional? value = tp.binding.local_variable_get(param_name) method_paramater.default_value = value end end end end |
#writable? ⇒ Boolean
Returns true when implementation_type writable?.
166 167 168 |
# File 'lib/peeky/method_info.rb', line 166 def writable? @implementation_type == :attr_writer end |