peeky 0.0.19 → 0.0.33

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.
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'peeky/version'
4
4
 
5
+ require 'peeky/api'
6
+
5
7
  require 'peeky/attr_info'
6
8
  require 'peeky/class_info'
7
9
  require 'peeky/method_info'
@@ -10,7 +12,9 @@ require 'peeky/parameter_info'
10
12
  require 'peeky/predicates/attr_reader_predicate'
11
13
  require 'peeky/predicates/attr_writer_predicate'
12
14
 
15
+ require 'peeky/renderer/class_debug_render'
13
16
  require 'peeky/renderer/class_interface_render'
17
+ require 'peeky/renderer/class_interface_yard_render'
14
18
  require 'peeky/renderer/method_call_minimum_params_render'
15
19
  require 'peeky/renderer/method_signature_render'
16
20
  require 'peeky/renderer/method_signature_with_debug_render'
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Peeky module provides access to the API via the
4
+ # module method Peeky.api
5
+ module Peeky
6
+ class << self
7
+ attr_accessor :api
8
+ end
9
+
10
+ # API has factory and creational patterns for easy usage
11
+ # of the Peeky reflection system
12
+ class Api
13
+ # Build a {Peeky::ClassInfo} structure based around a
14
+ # ruby class instance.
15
+ #
16
+ # ClassInfo stores information about the instance of a
17
+ # class that is passed in including methods, attr_accessors
18
+ # attr_readers and attr_writers.
19
+ def build_class_info(instance, lazy: true)
20
+ ci = Peeky::ClassInfo.new(instance)
21
+ ci.load unless lazy
22
+ ci
23
+ end
24
+
25
+ # Render a class using a predefined class renderer
26
+ def render_class(render_key, class_info: nil, instance: nil, **_opts)
27
+ raise 'Call render_class with class_info OR instance.' if class_info.nil? && instance.nil?
28
+ raise 'Call render_class with class_info OR instance, these parameters are mutually exclusive' if !class_info.nil? && !instance.nil?
29
+
30
+ renderer = class_renderer(render_key)
31
+
32
+ class_info = Peeky::ClassInfo.new(instance) if class_info.nil?
33
+
34
+ renderer.new(class_info).render
35
+ end
36
+
37
+ # Get a method renderer by :key
38
+ #
39
+ # TODO: Refactor to a configurable system
40
+ def method_renderer(key)
41
+ case key
42
+ when :signature
43
+ Peeky::Renderer::MethodSignatureRender
44
+ when :signature_with_debug
45
+ Peeky::Renderer::MethodSignatureWithDebugRender
46
+ when :call_minimum_params
47
+ Peeky::Renderer::MethodCallMinimumParamsRender
48
+ else
49
+ raise "Unknown method renderer: #{key}"
50
+ end
51
+ end
52
+
53
+ # Get a class renderer by :key
54
+ #
55
+ # TODO: Refactor to a configurable system
56
+ def class_renderer(key)
57
+ case key
58
+ when :class_debug
59
+ Peeky::Renderer::ClassDebugRender
60
+ when :class_interface
61
+ Peeky::Renderer::ClassInterfaceRender
62
+ when :class_interface_yard
63
+ Peeky::Renderer::ClassInterfaceYardRender
64
+ else
65
+ raise "Unknown class renderer: #{key}"
66
+ end
67
+ end
68
+
69
+ # def render_method()
70
+ # end
71
+ end
72
+ end
73
+
74
+ Peeky.api = Peeky::Api.new
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Peeky
4
- # Class Info stores information about the
5
- # class instance that you pass in.
4
+ # Class Info stores information about the class instance that is provided.
6
5
  #
7
6
  # The information is collected into MethodInfo objects
8
7
  # that live within the signatures accessor.
@@ -10,6 +9,7 @@ module Peeky
10
9
  # This information is then separated out into
11
10
  # :methods, :attr_accessors, :attr_readers and :attr_writers
12
11
  class ClassInfo
12
+ # Holds an instance to the class you are gathering information from
13
13
  attr_reader :instance
14
14
 
15
15
  # Peak into class information
@@ -17,24 +17,123 @@ module Peeky
17
17
  @instance = instance
18
18
  end
19
19
 
20
- def class_name
20
+ def to_s
21
+ class_full_name
22
+ end
23
+
24
+ # Load class_info
25
+ #
26
+ # Accessing information about methods and parameters is currently
27
+ # lazy-loaded via memoization.
28
+ #
29
+ # At times during debug or other edge cases, it may be useful to
30
+ # pre-load this information early.
31
+ def load
32
+ ruby_instance_methods
33
+ ruby_instance_method_names
34
+ signatures
35
+ end
36
+
37
+ # Class full name includes the module namespace
38
+ def class_full_name
21
39
  instance.class.name
22
40
  end
23
41
 
42
+ # Class name
43
+ def class_name
44
+ @_class_name ||= class_full_name.to_s.gsub(/^.*::/, '')
45
+ # instance.class.name.split('::').last
46
+ end
47
+
48
+ # Module name
49
+ def module_name
50
+ @_module_name ||= class_full_name.to_s.gsub(/(.*)::.*/, '\1')
51
+ end
52
+
53
+ # Get a list of :attr_accessor on the class
54
+ # @return [Array<AttrInfo>] list of AttrInfo where type is :attr_accessor
24
55
  def accessors
25
- @accessors ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_accessor }
56
+ @_accessors ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_accessor }
57
+ end
58
+
59
+ # Get a list of :attr_accessors ordered the way they are in the source code
60
+ # @return [Array<AttrInfo>] list of AttrInfo where type is :attr_accessor
61
+ def accessors_source_order
62
+ # TODO: This feature is required
63
+ # May be best to have a sort object that can be created for each type of ordering that is needed
64
+ accessors
26
65
  end
27
66
 
67
+ # Attribute infos
68
+ def attribute_infos
69
+ @_attribute_infos ||= begin
70
+ grouped_method_infos = signatures.select { |signature| signature.readable? || signature.writable? }.group_by(&:clean_name)
71
+
72
+ grouped_method_infos.keys.map { |key| AttrInfo.create(*grouped_method_infos[key]) }
73
+ end
74
+ end
75
+
76
+ # Method by name
77
+ #
78
+ # @param name [String] name (required)
79
+ def method_by_name(name)
80
+ signatures_by_name(name, filter_type: :method).first
81
+ end
82
+
83
+ # Get a list methods
84
+ # @return [Array<MethodInfo>] list of MethodInfo where type is :method
85
+ def methods
86
+ @_methods ||= signatures.select { |signature| signature.implementation_type == :method }
87
+ end
88
+
89
+ # Get a list methods ordered the way they are in the source code
90
+ # @return [Array<MethodInfo>] list of MethodInfo
91
+ def methods_source_order
92
+ # TODO: This feature is required
93
+ # May be best to have a sort object that can be created for each type of ordering that is needed
94
+ methods
95
+ end
96
+
97
+ # Reader by name
98
+ #
99
+ # @param name [String] name (required)
100
+ def reader_by_name(name)
101
+ signatures_by_name(name, filter_type: :attr_reader).first
102
+ end
103
+
104
+ # Get a list of :attr_reader on the class
105
+ # @return [Array<AttrInfo>] list of AttrInfo where type is :attr_accessor
28
106
  def readers
29
- @readers ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_reader }
107
+ @_readers ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_reader }
30
108
  end
31
109
 
110
+ # Get a list of :attr_reader ordered the way they are in the source code
111
+ # @return [Array<AttrInfo>] list of AttrInfo where type is :attr_reader
112
+ def readers_source_order
113
+ # TODO: This feature is required
114
+ # May be best to have a sort object that can be created for each type of ordering that is needed
115
+ readers
116
+ end
117
+
118
+ # Get a list of :attr_writer on the class
119
+ # @return [Array<AttrInfo>] list of AttrInfo where type is :attr_writer
32
120
  def writers
33
- @writers ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_writer }
121
+ @_writers ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_writer }
34
122
  end
35
123
 
36
- def methods
37
- @methods ||= signatures.select { |signature| signature.implementation_type == :method }
124
+ # Get a list of :attr_writer ordered the way they are in the source code
125
+ # @return [Array<AttrInfo>] list of AttrInfo where type is :attr_writer
126
+ def writers_source_order
127
+ # TODO: This feature is required
128
+ # May be best to have a sort object that can be created for each type of ordering that is needed
129
+ writers
130
+ end
131
+
132
+ # Writer by name
133
+ #
134
+ # @param name [String] name (required)
135
+ def writer_by_name(name)
136
+ signatures_by_name(name, filter_type: :attr_writer).first
38
137
  end
39
138
 
40
139
  # def signatures(types = [:instance])
@@ -42,36 +141,36 @@ module Peeky
42
141
  # such as static, private vs public
43
142
  # deep, deep_to_level, this_instance.
44
143
  def signatures
45
- @signatures ||= ruby_instance_methods.map { |im| MethodInfo.new(im, @instance) }
46
- end
47
-
48
- def signatures_by_name(name)
49
- signatures.select { |im| im.name == name }
144
+ @_signatures ||= ruby_instance_methods.map { |im| MethodInfo.new(im, @instance) }
50
145
  end
51
146
 
147
+ # Signatures by clean name
148
+ #
149
+ # @param clean_name [String] clean name (required)
52
150
  def signatures_by_clean_name(clean_name)
53
151
  signatures.select { |im| im.clean_name == clean_name }
54
152
  end
55
153
 
56
- def attribute_infos
57
- @attribute_infos ||= begin
58
- grouped_method_infos = signatures.select { |signature| signature.readable? || signature.writable? }.group_by(&:clean_name)
154
+ # Signatures by name
155
+ #
156
+ # @param name [String] name (required)
157
+ # @param filter_type [String] filter_type: <value for filter type> (optional)
158
+ def signatures_by_name(name, filter_type: :all)
159
+ return signatures.select { |im| im.name == name } if filter_type == :all
59
160
 
60
- grouped_method_infos.keys.map { |key| AttrInfo.create(*grouped_method_infos[key]) }
61
- end
161
+ signatures.select { |im| im.name == name && im.implementation_type == filter_type }
62
162
  end
63
163
 
164
+ # Debug
165
+ #
166
+ # Refact: PATTERN: Come up it an debug inclusion system so that
167
+ # so that debug helpers can be included for development and excluded
168
+ # for production
169
+ # @param format [String] format: <value for format> (optional)
64
170
  def debug(format: [:signatures])
65
- if format == :method_names
66
- puts '-' * 70
67
- puts 'Method Names'
68
- puts '-' * 70
69
- ruby_instance_method_names.each do |method_name|
70
- puts method_name
71
- end
72
- end
171
+ debug_method_names if format.include?(:method_names)
73
172
 
74
- return unless format == :signatures
173
+ return unless format.include?(:signatures)
75
174
 
76
175
  puts '-' * 70
77
176
  puts 'Methods'
@@ -79,14 +178,25 @@ module Peeky
79
178
  signatures.each(&:debug)
80
179
  end
81
180
 
181
+ def debug_method_names
182
+ puts '-' * 70
183
+ puts 'Method Names'
184
+ puts '-' * 70
185
+ ruby_instance_method_names.each do |method_name|
186
+ puts method_name
187
+ end
188
+ end
189
+
82
190
  private
83
191
 
84
192
  def ruby_instance_method_names
85
- @ruby_instance_method_names ||= instance.class.instance_methods(false).sort
193
+ @_ruby_instance_method_names ||= instance.class.instance_methods(false).sort
86
194
  end
87
195
 
88
196
  def ruby_instance_methods
89
- @ruby_instance_methods ||= ruby_instance_method_names.map { |method_name| instance.method(method_name) }
197
+ @_ruby_instance_methods ||= ruby_instance_method_names.map { |method_name| instance.method(method_name) }
198
+ rescue StandardError => e
199
+ puts e
90
200
  end
91
201
  end
92
202
  end
@@ -0,0 +1,124 @@
1
+ module Peeky
2
+ module Example
3
+ # Yard sample
4
+ class YardSample
5
+ # A read write1
6
+ attr_accessor :a_read_write1
7
+
8
+ # A read write2
9
+ attr_accessor :a_read_write2
10
+
11
+ # A read write3
12
+ attr_accessor :a_read_write3
13
+
14
+ # B reader1
15
+ attr_reader :b_reader1
16
+
17
+ # B reader2
18
+ attr_reader :b_reader2
19
+
20
+ # E looks like an attr reader
21
+ attr_reader :e_looks_like_an_attr_reader
22
+
23
+ # C writer1
24
+ attr_writer :c_writer1
25
+
26
+ # C writer2
27
+ attr_writer :c_writer2
28
+
29
+ # Alpha sort1
30
+ def alpha_sort1
31
+ end
32
+
33
+ # Alpha sort2
34
+ def alpha_sort2
35
+ end
36
+
37
+ # D do something method
38
+ def d_do_something_method
39
+ end
40
+
41
+ # E method with required param
42
+ #
43
+ # @param first_name [String] first name (required)
44
+ def e_method_with_required_param(first_name)
45
+ end
46
+
47
+ # F method with required param and optional param
48
+ #
49
+ # @param first_name [String] first name (required)
50
+ # @param last_name [String] last name (optional)
51
+ def f_method_with_required_param_and_optional_param(first_name, last_name = nil)
52
+ end
53
+
54
+ # G method with required param and two optional params
55
+ #
56
+ # @param first_name [String] first name (required)
57
+ # @param last_name [String] last name (optional)
58
+ # @param age [String] age (optional)
59
+ def g_method_with_required_param_and_two_optional_params(first_name, last_name = nil, age = nil)
60
+ end
61
+
62
+ # H list of optional parameters
63
+ #
64
+ # @param command_args [Array<Object>] *command_args - list of command args
65
+ def h_list_of_optional_parameters(*command_args)
66
+ end
67
+
68
+ # I method with two required params and list of optional params
69
+ #
70
+ # @param first_name [String] first name (required)
71
+ # @param last_name [String] last name (required)
72
+ # @param alias_names [Array<Object>] *alias_names - list of alias names
73
+ def i_method_with_two_required_params_and_list_of_optional_params(first_name, last_name, *alias_names)
74
+ end
75
+
76
+ # J method with list of named arguments
77
+ #
78
+ # @param options [<key: value>...] **options - list of key/values
79
+ def j_method_with_list_of_named_arguments(**options)
80
+ end
81
+
82
+ # K method with block
83
+ #
84
+ # @param code_block [Block] &code_block
85
+ def k_method_with_block(&code_block)
86
+ end
87
+
88
+ # L method with key value param required
89
+ #
90
+ # @param name [String] name: <value for name> (required)
91
+ def l_method_with_key_value_param_required(name:)
92
+ end
93
+
94
+ # N method with key value param required and optional key value
95
+ #
96
+ # @param last_name [String] last_name: <value for last name> (required)
97
+ # @param salutation [String] salutation: <value for salutation> (optional)
98
+ def n_method_with_key_value_param_required_and_optional_key_value(last_name:, salutation: nil)
99
+ end
100
+
101
+ # P available?
102
+
103
+ # @return [Boolean] true when p available?
104
+ def p_available?
105
+ end
106
+
107
+ # Q danger will robinson!
108
+ def q_danger_will_robinson!
109
+ end
110
+
111
+ # Z complex
112
+ #
113
+ # @param aaa [String] aaa (required)
114
+ # @param bbb [String] bbb (optional)
115
+ # @param ccc [Array<Object>] *ccc - list of ccc
116
+ # @param ddd [String] ddd: <value for ddd> (required)
117
+ # @param eee [String] eee: <value for eee> (optional)
118
+ # @param fff [<key: value>...] **fff - list of key/values
119
+ # @param ggg [Block] &ggg
120
+ def z_complex(aaa, bbb = nil, *ccc, ddd:, eee: nil, **fff, &ggg)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -12,18 +12,19 @@ module Peeky
12
12
  attr_accessor :parameters
13
13
 
14
14
  # MethodInfo delegates to the underlying ruby method object
15
- attr_reader :method
15
+ attr_reader :focal_method
16
16
 
17
- def_delegators :method, :name, :receiver, :arity, :super_method
17
+ def_delegators :focal_method, :name, :receiver, :arity, :super_method
18
18
 
19
19
  # Stage 2 is the method likely to be an attribute reader or writer
20
20
 
21
- # Implemented As indicates the probable representation of this
21
+ # Implementation type indicates the probable representation of this
22
22
  # method in ruby, was it `def method` or `attr_reader` / `attr_writer`
23
23
  attr_reader :implementation_type
24
24
 
25
+ # TODO: target_instance is required...
25
26
  def initialize(method, target_instance = nil)
26
- @method = method
27
+ @focal_method = method
27
28
  @parameters = ParameterInfo.from_method(method)
28
29
  # stage 1
29
30
  # @implementation_type = :method