peeky 0.0.19 → 0.0.25
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +4 -0
- data/Gemfile +6 -3
- data/Guardfile +4 -4
- data/README-stories.md +32 -4
- data/README.md +1 -5
- data/lib/peeky.rb +3 -0
- data/lib/peeky/api.rb +70 -0
- data/lib/peeky/class_info.rb +126 -22
- data/lib/peeky/example/yard_sample.rb +123 -0
- data/lib/peeky/method_info.rb +5 -4
- data/lib/peeky/predicates/attr_reader_predicate.rb +16 -4
- data/lib/peeky/predicates/attr_writer_predicate.rb +8 -0
- data/lib/peeky/renderer/class_interface_render.rb +9 -9
- data/lib/peeky/renderer/class_interface_yard_render.rb +142 -0
- data/lib/peeky/renderer/method_call_minimum_params_render.rb +4 -5
- data/lib/peeky/renderer/method_signature_render.rb +44 -13
- data/lib/peeky/renderer/method_signature_with_debug_render.rb +11 -11
- data/lib/peeky/tools/generate_yard_documentation.rb +19 -0
- data/lib/peeky/version.rb +1 -1
- data/peeky.gemspec +2 -1
- metadata +22 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75fed761de619d444f8e84f4e08df5df41e9f12b89e95051b60dd0f60bafa57e
|
|
4
|
+
data.tar.gz: 05e1ba1ec76ffe0689f536e8e2c78c86fd16570051212ca9031ef3cf5f302e9b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19bb5a15dc9c0db1a5346632f448da2ff7396f247c474a89b1dee7c2097e1fdf824bce8227a35762bc85db49d4301463f613f78999a20f1656edb870e4eabb51
|
|
7
|
+
data.tar.gz: 89ae53bd7a7a840a92214337bc7a08c5e813eab892a94391cb69b2e27a0ad87546c7489f03c710f20328b770abafd3ccf45c92a5bdaf22ed0d5ffb2b93fcd2cf
|
data/.rubocop.yml
CHANGED
|
@@ -4,8 +4,23 @@ AllCops:
|
|
|
4
4
|
NewCops: enable
|
|
5
5
|
Exclude:
|
|
6
6
|
- "_/**/*"
|
|
7
|
+
- "lib/peeky/example/yard_sample.rb"
|
|
7
8
|
|
|
8
9
|
# My Preferences - Start
|
|
10
|
+
Style/EmptyMethod:
|
|
11
|
+
Exclude:
|
|
12
|
+
- "**/spec/**/*"
|
|
13
|
+
Metrics/ParameterLists:
|
|
14
|
+
Exclude:
|
|
15
|
+
- "**/spec/**/*"
|
|
16
|
+
Layout/EmptyLineBetweenDefs:
|
|
17
|
+
Exclude:
|
|
18
|
+
- "**/spec/**/*"
|
|
19
|
+
|
|
20
|
+
Lint/AmbiguousBlockAssociation:
|
|
21
|
+
Exclude:
|
|
22
|
+
- "**/spec/**/*"
|
|
23
|
+
|
|
9
24
|
Style/AccessorGrouping:
|
|
10
25
|
Enabled: false
|
|
11
26
|
|
|
@@ -16,6 +31,7 @@ Layout/SpaceBeforeComma:
|
|
|
16
31
|
Metrics/BlockLength:
|
|
17
32
|
Exclude:
|
|
18
33
|
- "**/spec/*"
|
|
34
|
+
- "*.gemspec"
|
|
19
35
|
ExcludedMethods:
|
|
20
36
|
- configure
|
|
21
37
|
- context
|
data/.rubocop_todo.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -5,13 +5,16 @@ source 'https://rubygems.org'
|
|
|
5
5
|
# Specify your gem's dependencies in poc_github_ap.gemspec
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
|
+
group :development do
|
|
9
|
+
# pry on steroids
|
|
10
|
+
gem 'pry-coolline', github: 'owst/pry-coolline', branch: 'support_new_pry_config_api'
|
|
11
|
+
gem 'jazz_fingers'
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
group :development, :test do
|
|
9
15
|
gem 'guard-bundler'
|
|
10
16
|
gem 'guard-rspec'
|
|
11
17
|
gem 'guard-rubocop'
|
|
12
|
-
# pry on steroids
|
|
13
|
-
# gem 'pry-coolline', github: 'owst/pry-coolline', branch: 'support_new_pry_config_api'
|
|
14
|
-
gem 'jazz_fingers'
|
|
15
18
|
gem 'rake', '~> 12.0'
|
|
16
19
|
# this is used for cmdlets 'self-executing gems'
|
|
17
20
|
gem 'rake-compiler'
|
data/Guardfile
CHANGED
|
@@ -23,8 +23,8 @@ group :green_pass_then_cop, halt_on_fail: true do
|
|
|
23
23
|
watch(%r{^lib/peeky/commands/(.+)\.rb$}) { |m| "spec/unit/commands/#{m[1]}_spec.rb" }
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
guard :rubocop, all_on_start: false, cli: ['--format', 'clang'] do
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
26
|
+
# guard :rubocop, all_on_start: false, cli: ['--format', 'clang'] do
|
|
27
|
+
# watch(%r{.+\.rb$})
|
|
28
|
+
# watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
|
|
29
|
+
# end
|
|
30
30
|
end
|
data/README-stories.md
CHANGED
|
@@ -4,7 +4,37 @@
|
|
|
4
4
|
|
|
5
5
|
As a Ruby Developer, I should be able to Reverse engineer classes and methods, so that I can document and understand them
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Development rader
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Tasks next on list
|
|
11
|
+
|
|
12
|
+
As a Developer, I can render a class with RDoc documentation, so that I do not have to manually type RDoc references
|
|
13
|
+
|
|
14
|
+
- Add simplified API with examples
|
|
15
|
+
- Start documenting usage instructions
|
|
16
|
+
|
|
17
|
+
As a Developer, I can use Peeky with a simple API, so that I use this GEM quickly
|
|
18
|
+
|
|
19
|
+
- Add simplified API with examples
|
|
20
|
+
- Start documenting usage instructions
|
|
21
|
+
|
|
22
|
+
As a Developer, I can quickly build requirements, so that I can document project features
|
|
23
|
+
|
|
24
|
+
- Add support for backlog stories and tasks
|
|
25
|
+
- Add usage instructions
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Stories and tasks
|
|
30
|
+
|
|
31
|
+
### Stories - completed
|
|
32
|
+
|
|
33
|
+
As a David, I can edify Karin, because she is cool
|
|
34
|
+
|
|
35
|
+
- karin_is_awesome
|
|
36
|
+
- i_am_very_grateful_for_karin
|
|
37
|
+
- karin_the_beautiful
|
|
8
38
|
|
|
9
39
|
As a Developer, I can render a class with instance attributes and methods, So that I can quickly mock out an entire class
|
|
10
40
|
|
|
@@ -35,15 +65,13 @@ As a Developer, I should be able to interrogate class instance information, so t
|
|
|
35
65
|
- ClassInfo stores information about a ruby class. Only support instance methods
|
|
36
66
|
|
|
37
67
|
|
|
38
|
-
|
|
39
|
-
|
|
68
|
+
##$ Tasks - completed
|
|
40
69
|
|
|
41
70
|
Setup GitHub Action (test and lint)
|
|
42
71
|
|
|
43
72
|
- Setup Rspec action
|
|
44
73
|
- Setup RuboCop action
|
|
45
74
|
|
|
46
|
-
|
|
47
75
|
Setup new Ruby GEM
|
|
48
76
|
|
|
49
77
|
- Build out a standard GEM structure
|
data/README.md
CHANGED
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> Peeky is a Ruby GEM for peaking into ruby classes and extracting meta
|
|
4
4
|
|
|
5
|
-
Welcome to your new ruby gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/peeky`.
|
|
6
|
-
|
|
7
5
|
When using the source code for this gem, start by running `bin/setup` to install locally or `bundle install`
|
|
8
6
|
|
|
9
|
-
To experiment with that code, run `bin/console` for an interactive prompt or run `exe/peeky` to see a list of commands.
|
|
10
|
-
|
|
11
7
|
## Installation
|
|
12
8
|
|
|
13
9
|
Add this line to your application's Gemfile:
|
|
@@ -62,7 +58,7 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
62
58
|
|
|
63
59
|
## Code of Conduct
|
|
64
60
|
|
|
65
|
-
Everyone interacting in the Peeky project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the
|
|
61
|
+
Everyone interacting in the Peeky project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the.
|
|
66
62
|
|
|
67
63
|
## Copyright
|
|
68
64
|
|
data/lib/peeky.rb
CHANGED
|
@@ -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'
|
|
@@ -11,6 +13,7 @@ require 'peeky/predicates/attr_reader_predicate'
|
|
|
11
13
|
require 'peeky/predicates/attr_writer_predicate'
|
|
12
14
|
|
|
13
15
|
require 'peeky/renderer/class_interface_render'
|
|
16
|
+
require 'peeky/renderer/class_interface_yard_render'
|
|
14
17
|
require 'peeky/renderer/method_call_minimum_params_render'
|
|
15
18
|
require 'peeky/renderer/method_signature_render'
|
|
16
19
|
require 'peeky/renderer/method_signature_with_debug_render'
|
data/lib/peeky/api.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
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)
|
|
20
|
+
Peeky::ClassInfo.new(instance)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Render a class using a predefined class renderer
|
|
24
|
+
def render_class(render_key, class_info: nil, instance: nil, **_opts)
|
|
25
|
+
raise 'Call render_class with class_info OR instance.' if class_info.nil? && instance.nil?
|
|
26
|
+
raise 'Call render_class with class_info OR instance, these parameters are mutually exclusive' if !class_info.nil? && !instance.nil?
|
|
27
|
+
|
|
28
|
+
renderer = class_renderer(render_key)
|
|
29
|
+
|
|
30
|
+
class_info = Peeky::ClassInfo.new(instance) if class_info.nil?
|
|
31
|
+
|
|
32
|
+
renderer.new(class_info).render
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get a method renderer by :key
|
|
36
|
+
#
|
|
37
|
+
# TODO: Refactor to a configurable system
|
|
38
|
+
def method_renderer(key)
|
|
39
|
+
case key
|
|
40
|
+
when :signature
|
|
41
|
+
Peeky::Renderer::MethodSignatureRender
|
|
42
|
+
when :signature_with_debug
|
|
43
|
+
Peeky::Renderer::MethodSignatureWithDebugRender
|
|
44
|
+
when :call_minimum_params
|
|
45
|
+
Peeky::Renderer::MethodCallMinimumParamsRender
|
|
46
|
+
else
|
|
47
|
+
raise "Unknown method renderer: #{key}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Get a class renderer by :key
|
|
52
|
+
#
|
|
53
|
+
# TODO: Refactor to a configurable system
|
|
54
|
+
def class_renderer(key)
|
|
55
|
+
case key
|
|
56
|
+
when :class_interface
|
|
57
|
+
Peeky::Renderer::ClassInterfaceRender
|
|
58
|
+
when :class_interface_yard
|
|
59
|
+
Peeky::Renderer::ClassInterfaceYardRender
|
|
60
|
+
else
|
|
61
|
+
raise "Unknown class renderer: #{key}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# def render_method()
|
|
66
|
+
# end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
Peeky.api = Peeky::Api.new
|
data/lib/peeky/class_info.rb
CHANGED
|
@@ -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,106 @@ module Peeky
|
|
|
17
17
|
@instance = instance
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
# Class full name includes the module namespace
|
|
21
|
+
def class_full_name
|
|
21
22
|
instance.class.name
|
|
22
23
|
end
|
|
23
24
|
|
|
25
|
+
# Class name
|
|
26
|
+
def class_name
|
|
27
|
+
@_class_name ||= class_full_name.to_s.gsub(/^.*::/, '')
|
|
28
|
+
# instance.class.name.split('::').last
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Module name
|
|
32
|
+
def module_name
|
|
33
|
+
@_module_name ||= class_full_name.to_s.gsub(/(.*)::.*/, '\1')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Get a list of :attr_accessor on the class
|
|
37
|
+
# @return [Array<AttrInfo>] list of AttrInfo where type is :attr_accessor
|
|
24
38
|
def accessors
|
|
25
|
-
@
|
|
39
|
+
@_accessors ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_accessor }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Get a list of :attr_accessors ordered the way they are in the source code
|
|
43
|
+
# @return [Array<AttrInfo>] list of AttrInfo where type is :attr_accessor
|
|
44
|
+
def accessors_source_order
|
|
45
|
+
# TODO: This feature is required
|
|
46
|
+
# May be best to have a sort object that can be created for each type of ordering that is needed
|
|
47
|
+
accessors
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Attribute infos
|
|
51
|
+
def attribute_infos
|
|
52
|
+
@_attribute_infos ||= begin
|
|
53
|
+
grouped_method_infos = signatures.select { |signature| signature.readable? || signature.writable? }.group_by(&:clean_name)
|
|
54
|
+
|
|
55
|
+
grouped_method_infos.keys.map { |key| AttrInfo.create(*grouped_method_infos[key]) }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Method by name
|
|
60
|
+
#
|
|
61
|
+
# @param name [String] name (required)
|
|
62
|
+
def method_by_name(name)
|
|
63
|
+
signatures_by_name(name, filter_type: :method).first
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Get a list methods
|
|
67
|
+
# @return [Array<MethodInfo>] list of MethodInfo where type is :method
|
|
68
|
+
def methods
|
|
69
|
+
@_methods ||= signatures.select { |signature| signature.implementation_type == :method }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Get a list methods ordered the way they are in the source code
|
|
73
|
+
# @return [Array<MethodInfo>] list of MethodInfo
|
|
74
|
+
def methods_source_order
|
|
75
|
+
# TODO: This feature is required
|
|
76
|
+
# May be best to have a sort object that can be created for each type of ordering that is needed
|
|
77
|
+
methods
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Reader by name
|
|
81
|
+
#
|
|
82
|
+
# @param name [String] name (required)
|
|
83
|
+
def reader_by_name(name)
|
|
84
|
+
signatures_by_name(name, filter_type: :attr_reader).first
|
|
26
85
|
end
|
|
27
86
|
|
|
87
|
+
# Get a list of :attr_reader on the class
|
|
88
|
+
# @return [Array<AttrInfo>] list of AttrInfo where type is :attr_accessor
|
|
28
89
|
def readers
|
|
29
|
-
@
|
|
90
|
+
@_readers ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_reader }
|
|
30
91
|
end
|
|
31
92
|
|
|
93
|
+
# Get a list of :attr_reader ordered the way they are in the source code
|
|
94
|
+
# @return [Array<AttrInfo>] list of AttrInfo where type is :attr_reader
|
|
95
|
+
def readers_source_order
|
|
96
|
+
# TODO: This feature is required
|
|
97
|
+
# May be best to have a sort object that can be created for each type of ordering that is needed
|
|
98
|
+
readers
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Get a list of :attr_writer on the class
|
|
102
|
+
# @return [Array<AttrInfo>] list of AttrInfo where type is :attr_writer
|
|
32
103
|
def writers
|
|
33
|
-
@
|
|
104
|
+
@_writers ||= attribute_infos.select { |attribute_info| attribute_info.type == :attr_writer }
|
|
34
105
|
end
|
|
35
106
|
|
|
36
|
-
|
|
37
|
-
|
|
107
|
+
# Get a list of :attr_writer ordered the way they are in the source code
|
|
108
|
+
# @return [Array<AttrInfo>] list of AttrInfo where type is :attr_writer
|
|
109
|
+
def writers_source_order
|
|
110
|
+
# TODO: This feature is required
|
|
111
|
+
# May be best to have a sort object that can be created for each type of ordering that is needed
|
|
112
|
+
writers
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Writer by name
|
|
116
|
+
#
|
|
117
|
+
# @param name [String] name (required)
|
|
118
|
+
def writer_by_name(name)
|
|
119
|
+
signatures_by_name(name, filter_type: :attr_writer).first
|
|
38
120
|
end
|
|
39
121
|
|
|
40
122
|
# def signatures(types = [:instance])
|
|
@@ -42,27 +124,45 @@ module Peeky
|
|
|
42
124
|
# such as static, private vs public
|
|
43
125
|
# deep, deep_to_level, this_instance.
|
|
44
126
|
def signatures
|
|
45
|
-
@
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def signatures_by_name(name)
|
|
49
|
-
signatures.select { |im| im.name == name }
|
|
127
|
+
@_signatures ||= ruby_instance_methods.map { |im| MethodInfo.new(im, @instance) }
|
|
50
128
|
end
|
|
51
129
|
|
|
130
|
+
# Signatures by clean name
|
|
131
|
+
#
|
|
132
|
+
# @param clean_name [String] clean name (required)
|
|
52
133
|
def signatures_by_clean_name(clean_name)
|
|
53
134
|
signatures.select { |im| im.clean_name == clean_name }
|
|
54
135
|
end
|
|
55
136
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
137
|
+
# Signatures by name
|
|
138
|
+
#
|
|
139
|
+
# @param name [String] name (required)
|
|
140
|
+
# @param filter_type [String] filter_type: <value for filter type> (optional)
|
|
141
|
+
def signatures_by_name(name, filter_type: :all)
|
|
142
|
+
return signatures.select { |im| im.name == name } if filter_type == :all
|
|
59
143
|
|
|
60
|
-
|
|
61
|
-
|
|
144
|
+
signatures.select { |im| im.name == name && im.implementation_type == filter_type }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Build (not sure where I am going with this yet)
|
|
148
|
+
# TODO: Refact: Currently the idea is to pre-load data
|
|
149
|
+
# this is slower when you are not accessing things, but
|
|
150
|
+
# it is easier to debug, so think about what I really want
|
|
151
|
+
# here
|
|
152
|
+
def build()
|
|
153
|
+
ruby_instance_methods
|
|
154
|
+
ruby_instance_method_names
|
|
155
|
+
signatures
|
|
62
156
|
end
|
|
63
157
|
|
|
158
|
+
# Debug
|
|
159
|
+
#
|
|
160
|
+
# Refact: PATTERN: Come up it an debug inclusion system so that
|
|
161
|
+
# so that debug helpers can be included for development and excluded
|
|
162
|
+
# for production
|
|
163
|
+
# @param format [String] format: <value for format> (optional)
|
|
64
164
|
def debug(format: [:signatures])
|
|
65
|
-
if format
|
|
165
|
+
if format.include?(:method_names)
|
|
66
166
|
puts '-' * 70
|
|
67
167
|
puts 'Method Names'
|
|
68
168
|
puts '-' * 70
|
|
@@ -71,7 +171,7 @@ module Peeky
|
|
|
71
171
|
end
|
|
72
172
|
end
|
|
73
173
|
|
|
74
|
-
return unless format
|
|
174
|
+
return unless format.include?(:signatures)
|
|
75
175
|
|
|
76
176
|
puts '-' * 70
|
|
77
177
|
puts 'Methods'
|
|
@@ -82,11 +182,15 @@ module Peeky
|
|
|
82
182
|
private
|
|
83
183
|
|
|
84
184
|
def ruby_instance_method_names
|
|
85
|
-
@
|
|
185
|
+
@_ruby_instance_method_names ||= instance.class.instance_methods(false).sort
|
|
86
186
|
end
|
|
87
187
|
|
|
88
188
|
def ruby_instance_methods
|
|
89
|
-
|
|
189
|
+
begin
|
|
190
|
+
@_ruby_instance_methods ||= ruby_instance_method_names.map { |method_name| instance.method(method_name) }
|
|
191
|
+
rescue => exception
|
|
192
|
+
puts exception
|
|
193
|
+
end
|
|
90
194
|
end
|
|
91
195
|
end
|
|
92
196
|
end
|
|
@@ -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
|
data/lib/peeky/method_info.rb
CHANGED
|
@@ -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 :
|
|
15
|
+
attr_reader :focal_method
|
|
16
16
|
|
|
17
|
-
def_delegators :
|
|
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
|
-
#
|
|
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
|
-
@
|
|
27
|
+
@focal_method = method
|
|
27
28
|
@parameters = ParameterInfo.from_method(method)
|
|
28
29
|
# stage 1
|
|
29
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
|
-
|
|
29
|
+
@#{method_name} = '#{new_value}' # eg. @variable = 'a3bj7a3bj7a3bj7a3bj7'
|
|
22
30
|
RUBY
|
|
23
|
-
|
|
24
|
-
|
|
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)
|
|
@@ -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,
|
|
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
|
|
@@ -4,14 +4,54 @@ module Peeky
|
|
|
4
4
|
module Renderer
|
|
5
5
|
# Render: Method Signature in compact format
|
|
6
6
|
#
|
|
7
|
-
# Example output:
|
|
7
|
+
# === Example output (:default):
|
|
8
|
+
# def simple(first_param)
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# def complex(aaa, bbb = nil, *ccc, ddd:, eee: nil, **fff, &ggg)
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# === Example output (:compact):
|
|
8
15
|
# def simple(first_param); end
|
|
9
16
|
# def complex(aaa, bbb = nil, *ccc, ddd:, eee: nil, **fff, &ggg); end
|
|
10
17
|
class MethodSignatureRender
|
|
18
|
+
# Indentation prefix as a string.
|
|
19
|
+
#
|
|
20
|
+
# Defaults to ''
|
|
21
|
+
#
|
|
22
|
+
# If you were writing a class into a file with an existing
|
|
23
|
+
# module, you may set the indent to ' ' if you wanted this
|
|
24
|
+
# render to indent by two spaces
|
|
25
|
+
attr_accessor :indent
|
|
26
|
+
|
|
27
|
+
# Style of method rendering [:default, :compact]
|
|
28
|
+
#
|
|
29
|
+
# default:: will render +def method_name+ and +end+ on separate lines
|
|
30
|
+
# compact:: will render +def method_name+ and +end+ on same line
|
|
31
|
+
# @return [Symbol] style
|
|
32
|
+
attr_accessor :style
|
|
33
|
+
|
|
34
|
+
# Method signature stores a MethodInfo object
|
|
11
35
|
attr_reader :method_signature
|
|
12
36
|
|
|
13
|
-
def initialize(method_signature)
|
|
37
|
+
def initialize(method_signature, **_opts)
|
|
14
38
|
@method_signature = method_signature
|
|
39
|
+
@indent = ''
|
|
40
|
+
@style = :compact
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Render the method signature in the selected style
|
|
44
|
+
def render
|
|
45
|
+
output = []
|
|
46
|
+
if @style == :compact
|
|
47
|
+
signature = "#{render_signature};"
|
|
48
|
+
output.push "#{signature.ljust(80)}#{render_end}"
|
|
49
|
+
end
|
|
50
|
+
if @style == :default
|
|
51
|
+
output.push render_signature
|
|
52
|
+
output.push render_end
|
|
53
|
+
end
|
|
54
|
+
output.join("\n")
|
|
15
55
|
end
|
|
16
56
|
|
|
17
57
|
def render_signature
|
|
@@ -19,20 +59,11 @@ module Peeky
|
|
|
19
59
|
|
|
20
60
|
formatted_parameters = method_signature.parameters.map(&:signature_format).join(', ')
|
|
21
61
|
params = formatted_parameters.length.zero? ? '' : "(#{formatted_parameters})"
|
|
22
|
-
"def #{name}#{params}"
|
|
62
|
+
"#{@indent}def #{name}#{params}"
|
|
23
63
|
end
|
|
24
64
|
|
|
25
65
|
def render_end
|
|
26
|
-
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def render
|
|
30
|
-
signature = "#{render_signature};"
|
|
31
|
-
"#{signature.ljust(80)}#{render_end}"
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def debug
|
|
35
|
-
puts render
|
|
66
|
+
"#{@indent}end"
|
|
36
67
|
end
|
|
37
68
|
end
|
|
38
69
|
end
|
|
@@ -22,14 +22,22 @@ module Peeky
|
|
|
22
22
|
# puts ggg # &ggg is block with many calling options, example - instance_eval(&block) if block_given?
|
|
23
23
|
# end
|
|
24
24
|
class MethodSignatureWithDebugRender
|
|
25
|
+
# Method signature stores a MethodInfo object
|
|
25
26
|
attr_reader :method_signature
|
|
26
27
|
|
|
27
|
-
def initialize(method_signature)
|
|
28
|
+
def initialize(method_signature, **_opts)
|
|
28
29
|
@method_signature = method_signature
|
|
29
30
|
|
|
30
31
|
@render_signature = Peeky::Renderer::MethodSignatureRender.new(method_signature)
|
|
31
32
|
end
|
|
32
33
|
|
|
34
|
+
# Render the method with debug statements for each parameter
|
|
35
|
+
def render
|
|
36
|
+
render_method
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
33
41
|
def render_method
|
|
34
42
|
name = method_signature.name
|
|
35
43
|
|
|
@@ -38,7 +46,7 @@ module Peeky
|
|
|
38
46
|
indent = ' '
|
|
39
47
|
output += "#{indent}puts 'method name: #{name}'\n"
|
|
40
48
|
|
|
41
|
-
output +=
|
|
49
|
+
output += render_debug_logic(indent, 30)
|
|
42
50
|
|
|
43
51
|
indent = ''
|
|
44
52
|
output += "#{indent}#{@render_signature.render_end}\n"
|
|
@@ -47,7 +55,7 @@ module Peeky
|
|
|
47
55
|
end
|
|
48
56
|
|
|
49
57
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
50
|
-
def
|
|
58
|
+
def render_debug_logic(indent, size)
|
|
51
59
|
output = ''
|
|
52
60
|
method_signature.parameters.each do |parameter|
|
|
53
61
|
line = ''
|
|
@@ -73,14 +81,6 @@ module Peeky
|
|
|
73
81
|
output
|
|
74
82
|
end
|
|
75
83
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
76
|
-
|
|
77
|
-
def render
|
|
78
|
-
render_method
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def debug
|
|
82
|
-
puts render
|
|
83
|
-
end
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
end
|
data/lib/peeky/version.rb
CHANGED
data/peeky.gemspec
CHANGED
|
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
|
6
6
|
spec.required_ruby_version = '>= 2.5'
|
|
7
7
|
spec.name = 'peeky'
|
|
8
8
|
spec.version = Peeky::VERSION
|
|
9
|
-
spec.authors = ['David
|
|
9
|
+
spec.authors = ['David Cruwys']
|
|
10
10
|
spec.email = ['david@ideasmen.com.au']
|
|
11
11
|
|
|
12
12
|
spec.summary = 'Extracting meta data from ruby classes'
|
|
@@ -41,5 +41,6 @@ Gem::Specification.new do |spec|
|
|
|
41
41
|
spec.require_paths = ['lib']
|
|
42
42
|
# spec.extensions = ['ext/peeky/extconf.rb']
|
|
43
43
|
|
|
44
|
+
spec.add_dependency 'activesupport'
|
|
44
45
|
# spec.add_dependency 'tty-box', '~> 0.5.0'
|
|
45
46
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: peeky
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.25
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- David
|
|
7
|
+
- David Cruwys
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-11-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2020-11-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activesupport
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
description: |2
|
|
14
28
|
Peeky is a Ruby GEM for peaking into ruby classes and extracting meta data.
|
|
15
29
|
You can use this meta data to recreate classes, interfaces, documentation etc.
|
|
@@ -40,16 +54,20 @@ files:
|
|
|
40
54
|
- hooks/pre-commit
|
|
41
55
|
- hooks/update-version
|
|
42
56
|
- lib/peeky.rb
|
|
57
|
+
- lib/peeky/api.rb
|
|
43
58
|
- lib/peeky/attr_info.rb
|
|
44
59
|
- lib/peeky/class_info.rb
|
|
60
|
+
- lib/peeky/example/yard_sample.rb
|
|
45
61
|
- lib/peeky/method_info.rb
|
|
46
62
|
- lib/peeky/parameter_info.rb
|
|
47
63
|
- lib/peeky/predicates/attr_reader_predicate.rb
|
|
48
64
|
- lib/peeky/predicates/attr_writer_predicate.rb
|
|
49
65
|
- lib/peeky/renderer/class_interface_render.rb
|
|
66
|
+
- lib/peeky/renderer/class_interface_yard_render.rb
|
|
50
67
|
- lib/peeky/renderer/method_call_minimum_params_render.rb
|
|
51
68
|
- lib/peeky/renderer/method_signature_render.rb
|
|
52
69
|
- lib/peeky/renderer/method_signature_with_debug_render.rb
|
|
70
|
+
- lib/peeky/tools/generate_yard_documentation.rb
|
|
53
71
|
- lib/peeky/version.rb
|
|
54
72
|
- peeky.gemspec
|
|
55
73
|
homepage: http://appydave.com/gems/peeky
|