peeky 0.0.14 → 0.0.28

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
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
+ # @return [Boolean] true when p available?
103
+ def p_available?
104
+ end
105
+
106
+ # Q danger will robinson!
107
+ def q_danger_will_robinson!
108
+ end
109
+
110
+ # Z complex
111
+ #
112
+ # @param aaa [String] aaa (required)
113
+ # @param bbb [String] bbb (optional)
114
+ # @param ccc [Array<Object>] *ccc - list of ccc
115
+ # @param ddd [String] ddd: <value for ddd> (required)
116
+ # @param eee [String] eee: <value for eee> (optional)
117
+ # @param fff [<key: value>...] **fff - list of key/values
118
+ # @param ggg [Block] &ggg
119
+ def z_complex(aaa, bbb = nil, *ccc, ddd:, eee: nil, **fff, &ggg)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -3,7 +3,8 @@
3
3
  require 'forwardable'
4
4
 
5
5
  module Peeky
6
- # Method Info
6
+ # Method info store a list of instance methods and attr_* for
7
+ # a ruby class.
7
8
  class MethodInfo
8
9
  extend Forwardable
9
10
 
@@ -11,18 +12,19 @@ module Peeky
11
12
  attr_accessor :parameters
12
13
 
13
14
  # MethodInfo delegates to the underlying ruby method object
14
- attr_reader :method
15
+ attr_reader :focal_method
15
16
 
16
- def_delegators :method, :name, :receiver, :arity, :super_method
17
+ def_delegators :focal_method, :name, :receiver, :arity, :super_method
17
18
 
18
19
  # Stage 2 is the method likely to be an attribute reader or writer
19
20
 
20
- # Implemented As indicates the probable representation of this
21
+ # Implementation type indicates the probable representation of this
21
22
  # method in ruby, was it `def method` or `attr_reader` / `attr_writer`
22
23
  attr_reader :implementation_type
23
24
 
25
+ # TODO: target_instance is required...
24
26
  def initialize(method, target_instance = nil)
25
- @method = method
27
+ @focal_method = method
26
28
  @parameters = ParameterInfo.from_method(method)
27
29
  # stage 1
28
30
  # @implementation_type = :method
@@ -7,27 +7,39 @@ module Peeky
7
7
  # Attr Reader Predicate will match true if the method info could be considered
8
8
  # a valid attr_reader
9
9
  class AttrReaderPredicate
10
+ # Match will return true if the method_info seems to be an :attr_reader
11
+ #
12
+ # @param instance [Object] instance the object that has this method (required)
13
+ # @param method_info [String] method info (required)
10
14
  def match(instance, method_info)
11
15
  return false unless prerequisites(instance, method_info)
12
16
 
13
- variable_name = "@#{method_info.name}"
14
17
  method_name = method_info.name
15
18
 
16
19
  # Refactor: Fragile
17
20
  # Really need to handle exceptions and types better
18
21
  # old_value = instance.send(method_name)
22
+
23
+ # This code works by
24
+ # 1. Set @name_of_method variable to random value
25
+ # 2. Call method name and see if it returns that value
26
+ # 3. Return match<true> if the values are equal
19
27
  new_value = SecureRandom.alphanumeric(20)
20
28
  code = <<-RUBY
21
- #{variable_name} = '#{new_value}' # @variable = 'a3bj7a3bj7a3bj7a3bj7'
29
+ @#{method_name} = '#{new_value}' # eg. @variable = 'a3bj7a3bj7a3bj7a3bj7'
22
30
  RUBY
23
- instance.instance_eval(code)
24
- current_value = instance.send(method_name)
31
+
32
+ cloned = instance.clone
33
+
34
+ cloned.instance_eval(code)
35
+ current_value = cloned.send(method_name)
25
36
  current_value == new_value
26
37
  end
27
38
 
28
39
  private
29
40
 
30
41
  def prerequisites(instance, method_info)
42
+ # look for obvious NON :attr_reader patterns
31
43
  return false if %w[! ? =].include?(method_info.name.to_s[-1..-1])
32
44
  return false unless method_info.parameters.length.zero?
33
45
  return false unless instance.respond_to?(method_info.name)
@@ -7,16 +7,24 @@ module Peeky
7
7
  # Attr Writer Predicate will match true if the method info could be considered
8
8
  # a valid attr_writer
9
9
  class AttrWriterPredicate
10
+ # Match will return true if the method_info seems to be an :attr_writer
11
+ #
12
+ # @param instance [Object] instance the object that has this method (required)
13
+ # @param method_info [String] method info (required)
10
14
  def match(instance, method_info)
11
15
  return false unless prerequisites(instance, method_info)
12
16
 
13
17
  param = method_info.parameters.first
18
+ # Taking advantage of an odd reflection concept in ruby where by
19
+ # method.parameters returns this array value [:req] for :attr_writer
20
+ # while ordinary methods return [:req, some_param_name]
14
21
  param.type == :param_required && param.name.empty?
15
22
  end
16
23
 
17
24
  private
18
25
 
19
26
  def prerequisites(instance, method_info)
27
+ # look for obvious NON :attr_writer patterns
20
28
  return false if %w[! ?].include?(method_info.name.to_s[-1..-1])
21
29
  return false unless method_info.name.to_s.end_with?('=')
22
30
  return false unless instance.respond_to?(method_info.name)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Peeky
4
4
  module Renderer
5
- # Class Interface Render
5
+ # Render: Class Interface
6
6
  #
7
7
  # Example output:
8
8
  # class SampleClassClassInterfaceRender
@@ -30,12 +30,14 @@ module Peeky
30
30
  # def z(aaa, bbb = nil, *ccc, ddd:, eee: nil, **fff, &ggg); end
31
31
  # end
32
32
  class ClassInterfaceRender
33
+ # ClassInfo with information about the class instance to be rendered.
33
34
  attr_reader :class_info
34
35
 
35
36
  def initialize(class_info)
36
37
  @class_info = class_info
37
38
  end
38
39
 
40
+ # Render the class interface
39
41
  def render
40
42
  @indent = ''
41
43
  output = []
@@ -53,30 +55,32 @@ module Peeky
53
55
  output.join("\n")
54
56
  end
55
57
 
58
+ private
59
+
56
60
  def render_start
57
- "#{@indent}class #{class_info.class_name}"
61
+ "#{@indent}class #{@class_info.class_name}"
58
62
  end
59
63
 
60
64
  def render_accessors
61
- result = class_info.accessors.map { |attr| "#{@indent}attr_accessor :#{attr.name}" }
65
+ result = @class_info.accessors.map { |attr| "#{@indent}attr_accessor :#{attr.name}" }
62
66
  result.push '' unless result.length.zero?
63
67
  result
64
68
  end
65
69
 
66
70
  def render_readers
67
- result = class_info.readers.map { |attr| "#{@indent}attr_reader :#{attr.name}" }
71
+ result = @class_info.readers.map { |attr| "#{@indent}attr_reader :#{attr.name}" }
68
72
  result.push '' unless result.length.zero?
69
73
  result
70
74
  end
71
75
 
72
76
  def render_writers
73
- result = class_info.writers.map { |attr| "#{@indent}attr_writer :#{attr.name}" }
77
+ result = @class_info.writers.map { |attr| "#{@indent}attr_writer :#{attr.name}" }
74
78
  result.push '' unless result.length.zero?
75
79
  result
76
80
  end
77
81
 
78
82
  def render_methods
79
- result = class_info.methods.map do |method_signature|
83
+ result = @class_info.methods.map do |method_signature|
80
84
  render_signature = Peeky::Renderer::MethodSignatureRender.new(method_signature)
81
85
  "#{@indent}#{render_signature.render}"
82
86
  end
@@ -87,10 +91,6 @@ module Peeky
87
91
  def render_end
88
92
  "#{@indent}end"
89
93
  end
90
-
91
- def debug
92
- puts render
93
- end
94
94
  end
95
95
  end
96
96
  end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require 'active_support/core_ext'
4
+ require 'active_support/core_ext/string'
5
+
6
+ module Peeky
7
+ module Renderer
8
+ # Render: Class Interface with YARD documentation
9
+ class ClassInterfaceYardRender
10
+ # Indentation prefix as a string, defaults to +''+
11
+ #
12
+ # If you were writing a class into a file with an existing
13
+ # module, you may set the indent to +' '+ if you wanted this
14
+ # render to indent by two spaces
15
+ attr_accessor :indent
16
+
17
+ # Default param type when documenting positional and named parameters.
18
+ # Defaults to <String>
19
+ attr_accessor :default_param_type
20
+
21
+ # Default param type when documenting splat *parameters.
22
+ # Defaults to <Object>
23
+ attr_accessor :default_splat_param_type
24
+
25
+ # ClassInfo with information about the class instance to be rendered.
26
+ attr_reader :class_info
27
+
28
+ def initialize(class_info)
29
+ @class_info = class_info
30
+ @indent = ''
31
+ @default_param_type = 'String'
32
+ @default_splat_param_type = 'Object'
33
+ end
34
+
35
+ # Render the class interface with YARD documentation
36
+ def render
37
+ output = []
38
+ output.push render_start
39
+ @indent += ' '
40
+ output += render_accessors
41
+ output += render_readers
42
+ output += render_writers
43
+ output += render_methods
44
+ output.pop if output.last == ''
45
+
46
+ @indent = @indent[0..-3]
47
+
48
+ output.push render_end
49
+
50
+ output.join("\n")
51
+ end
52
+
53
+ private
54
+
55
+ def render_start
56
+ [
57
+ "#{@indent}# #{@class_info.class_name.titleize.humanize}",
58
+ "#{@indent}class #{@class_info.class_name}"
59
+ ]
60
+ end
61
+
62
+ def render_accessors
63
+ result = []
64
+ @class_info.accessors.map.with_index do |attr, index|
65
+ result.push '' if index.positive?
66
+ result.push "#{@indent}# #{attr.name.to_s.humanize}"
67
+ result.push "#{@indent}attr_accessor :#{attr.name}"
68
+ end
69
+ result.push '' unless result.length.zero?
70
+ result
71
+ end
72
+
73
+ def render_readers
74
+ result = []
75
+ @class_info.readers.map.with_index do |attr, index|
76
+ result.push '' if index.positive?
77
+ result.push "#{@indent}# #{attr.name.to_s.humanize}"
78
+ result.push "#{@indent}attr_reader :#{attr.name}"
79
+ end
80
+ result.push '' unless result.length.zero?
81
+ result
82
+ end
83
+
84
+ def render_writers
85
+ result = []
86
+ class_info.writers.map.with_index do |attr, index|
87
+ result.push '' if index.positive?
88
+ result.push "#{@indent}# #{attr.name.to_s.humanize}"
89
+ result.push "#{@indent}attr_writer :#{attr.name}"
90
+ end
91
+ result.push '' unless result.length.zero?
92
+ result
93
+ end
94
+
95
+ # rubocop:disable Metrics/AbcSize, Metrics/BlockLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
96
+ def render_methods
97
+ result = []
98
+ class_info.methods.map.with_index do |method_signature, index|
99
+ result.push '' if index.positive?
100
+ result.push "#{@indent}# #{method_signature.name.to_s.humanize}"
101
+
102
+ method_signature.parameters.each_with_index do |parameter, param_index|
103
+ result.push "#{@indent}#" if param_index.zero?
104
+
105
+ case parameter.type
106
+ when :splat
107
+ result.push "#{@indent}# @param #{parameter.name} [Array<#{default_splat_param_type}>] *#{parameter.name} - list of #{parameter.name.to_s.humanize.downcase}"
108
+ when :double_splat
109
+ result.push "#{@indent}# @param #{parameter.name} [<key: value>...] **#{parameter.name} - list of key/values"
110
+ when :block
111
+ result.push "#{@indent}# @param #{parameter.name} [Block] &#{parameter.name}"
112
+ when :key_required
113
+ result.push "#{@indent}# @param #{parameter.name} [#{default_param_type}] #{parameter.name}: <value for #{parameter.name.to_s.humanize.downcase}> (required)"
114
+ when :key_optional
115
+ result.push "#{@indent}# @param #{parameter.name} [#{default_param_type}] #{parameter.name}: <value for #{parameter.name.to_s.humanize.downcase}> (optional)"
116
+ when :param_required
117
+ result.push "#{@indent}# @param #{parameter.name} [#{default_param_type}] #{parameter.name.to_s.humanize.downcase} (required)"
118
+ when :param_optional
119
+ result.push "#{@indent}# @param #{parameter.name} [#{default_param_type}] #{parameter.name.to_s.humanize.downcase} (optional)"
120
+ else
121
+ result.push "#{@indent}# @param #{parameter.name} [#{default_param_type}] #{parameter.name.to_s.humanize.downcase}"
122
+ end
123
+ end
124
+
125
+ result.push "#{@indent}# @return [Boolean] true when #{method_signature.name.to_s.humanize.downcase}" if method_signature.name.to_s.end_with?('?')
126
+
127
+ render_signature = Peeky::Renderer::MethodSignatureRender.new(method_signature)
128
+ render_signature.indent = @indent
129
+ render_signature.style = :default
130
+ result.push render_signature.render
131
+ end
132
+ result.push '' unless result.length.zero?
133
+ result
134
+ end
135
+ # rubocop:enable Metrics/AbcSize, Metrics/BlockLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
136
+
137
+ def render_end
138
+ "#{@indent}end"
139
+ end
140
+ end
141
+ end
142
+ end
@@ -8,13 +8,16 @@ module Peeky
8
8
  # instance.simple('first_param')
9
9
  # instance.complex('aaa', ddd: 'ddd')
10
10
  class MethodCallMinimumParamsRender
11
+ # Method signature stores a MethodInfo object
11
12
  attr_reader :method_signature
12
13
 
13
- def initialize(method_signature, instance_name = 'instance')
14
+ def initialize(method_signature, **opts)
15
+ instance_name = opts[:instance_name] || 'instance'
14
16
  @instance_name = instance_name
15
17
  @method_signature = method_signature
16
18
  end
17
19
 
20
+ # Render the a method call with minimal parameters
18
21
  def render
19
22
  name = method_signature.name
20
23
 
@@ -28,10 +31,6 @@ module Peeky
28
31
 
29
32
  "#{@instance_name}.#{name}#{params}"
30
33
  end
31
-
32
- def debug
33
- puts render
34
- end
35
34
  end
36
35
  end
37
36
  end