peeky 0.0.15 → 0.0.31

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.
@@ -20,11 +20,8 @@ module Peeky
20
20
  # type of the parameter
21
21
  attr_accessor :type
22
22
 
23
- # ruby code format when used in a signature
24
- attr_accessor :signature_format
25
-
26
- # minimal required usage in a call to the method with this paramater
27
- attr_accessor :minimal_call_format
23
+ # default value for positional or keyed parameters
24
+ attr_accessor :default_value
28
25
 
29
26
  def initialize(param)
30
27
  map(param)
@@ -58,47 +55,125 @@ module Peeky
58
55
  puts "minimal_call_format : #{minimal_call_format}"
59
56
  end
60
57
 
58
+ # ruby code formatted for use in a method signature
59
+ def signature_format
60
+ @_signature_format ||= begin
61
+ method_name = "signature_format_#{@type}".to_sym
62
+
63
+ m = method(method_name)
64
+ m.call
65
+ end
66
+ end
67
+
68
+ # minimal required usage in a call to the method with this paramater
69
+ def minimal_call_format
70
+ @_minimal_call_format ||= begin
71
+ method_name = "minimal_call_format_#{@type}".to_sym
72
+
73
+ if respond_to?(method_name, true)
74
+ m = method(method_name)
75
+ m.call
76
+ else
77
+ minimal_call_format_ignore
78
+ end
79
+ end
80
+ end
81
+
61
82
  private
62
83
 
63
84
  # Convert the limited information provided by ruby method.parameters
64
85
  # to a richer structure.
65
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
86
+ # rubocop:disable Metrics/CyclomaticComplexity
66
87
  def map(param)
67
88
  @name = param.length > 1 ? param[1].to_s : ''
68
89
 
90
+ @default_value = nil
91
+
69
92
  case param[0]
70
93
  when :req
71
94
  @type = :param_required
72
- @signature_format = name.to_s
73
- @minimal_call_format = "'#{name}'"
74
95
  when :opt
75
96
  @type = :param_optional
76
- @signature_format = "#{name} = nil"
77
- @minimal_call_format = ''
78
97
  when :rest
79
98
  @type = :splat
80
- @signature_format = "*#{name}"
81
- @minimal_call_format = ''
82
99
  when :keyreq
83
100
  @type = :key_required
84
- @signature_format = "#{name}:"
85
- @minimal_call_format = "#{name}: '#{name}'"
86
101
  when :key
87
102
  @type = :key_optional
88
- @signature_format = "#{name}: nil"
89
- @minimal_call_format = ''
90
103
  when :keyrest
91
104
  @type = :double_splat
92
- @signature_format = "**#{name}"
93
- @minimal_call_format = ''
94
105
  when :block
95
106
  @type = :block
96
- @signature_format = "&#{name}"
97
- @minimal_call_format = ''
98
107
  else
99
108
  raise 'unknown type'
100
109
  end
101
110
  end
102
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
111
+ # rubocop:enable Metrics/CyclomaticComplexity
112
+
113
+ # Signature format *: Is used to format a parameter when it is used
114
+ # inside of a method signature, eg. def my_method(p1, p2 = 'xyz', p3: :name_value)
115
+
116
+ def signature_format_param_required
117
+ name.to_s
118
+ end
119
+
120
+ def signature_format_param_optional
121
+ "#{name} = nil" # signature format needs to be moved to a method
122
+ end
123
+
124
+ def signature_format_splat
125
+ "*#{name}"
126
+ end
127
+
128
+ def signature_format_key_required
129
+ "#{name}:"
130
+ end
131
+
132
+ def signature_format_key_optional
133
+ "#{name}: nil"
134
+ end
135
+
136
+ def signature_format_double_splat
137
+ "**#{name}"
138
+ end
139
+
140
+ def signature_format_block
141
+ "&#{name}"
142
+ end
143
+
144
+ # Minimal call format *: Is used to format a call to a method with the least
145
+ # number of parameters needed to make it work.
146
+
147
+ def minimal_call_format_ignore
148
+ ''
149
+ end
150
+
151
+ def minimal_call_format_param_required
152
+ "'#{@name}'"
153
+ end
154
+
155
+ # def minimal_call_format_param_optional
156
+ # ''
157
+ # end
158
+
159
+ # def minimal_call_format_splat
160
+ # ''
161
+ # end
162
+
163
+ def minimal_call_format_key_required
164
+ "#{@name}: '#{@name}'"
165
+ end
166
+
167
+ # def minimal_call_format_key_optional
168
+ # ''
169
+ # end
170
+
171
+ # def minimal_call_format_double_splat
172
+ # ''
173
+ # end
174
+
175
+ # def minimal_call_format_block
176
+ # ''
177
+ # end
103
178
  end
104
179
  end
@@ -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,145 @@
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
+ if method_signature.name.to_s.end_with?('?')
126
+ result.push ''
127
+ result.push "#{@indent}# @return [Boolean] true when #{method_signature.name.to_s.humanize.downcase}"
128
+ end
129
+
130
+ render_signature = Peeky::Renderer::MethodSignatureRender.new(method_signature)
131
+ render_signature.indent = @indent
132
+ render_signature.style = :default
133
+ result.push render_signature.render
134
+ end
135
+ result.push '' unless result.length.zero?
136
+ result
137
+ end
138
+ # rubocop:enable Metrics/AbcSize, Metrics/BlockLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
139
+
140
+ def render_end
141
+ "#{@indent}end"
142
+ end
143
+ end
144
+ end
145
+ 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