advanced_code_generator 1.0.0
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 +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +17 -0
- data/.rubocop_todo.yml +23 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +217 -0
- data/Rakefile +12 -0
- data/code_generator.gemspec +44 -0
- data/lib/advanced_code_generator/generator.rb +298 -0
- data/lib/advanced_code_generator/method_config.rb +187 -0
- data/lib/advanced_code_generator/parameter.rb +113 -0
- data/lib/advanced_code_generator/version.rb +5 -0
- data/lib/advanced_code_generator.rb +11 -0
- data/rakelib/docs.rake +73 -0
- metadata +147 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 789748d3f9da47e662a6a064d1ec96b474c1d4c8575926a2cb0be6c171db38ba
|
|
4
|
+
data.tar.gz: fe9b5f6fe4222a4aa2af67b8cdc02eea3870c61df80a4e1873d1685104bd893f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6f21e274a7800a1fd5bd0c4b231d5c4a62acb253601d88e120a44436000bde70453e8056b8a2e54b24ace11b43e8d586296cf9c1756be8c390745f19177dd446
|
|
7
|
+
data.tar.gz: 9d96e6669bd01b946a59e29653805fd3bfcc2821f0a5113a98579343c435fec3211f1d0509f0ba9b0ce4a8e18641bef47b0d9f07b775452855bf21e803acae9d
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
plugins:
|
|
4
|
+
- rubocop-sorted_methods_by_call
|
|
5
|
+
|
|
6
|
+
AllCops:
|
|
7
|
+
NewCops: enable
|
|
8
|
+
TargetRubyVersion: 2.7
|
|
9
|
+
|
|
10
|
+
Layout/LineLength:
|
|
11
|
+
Max: 120
|
|
12
|
+
|
|
13
|
+
Gemspec/DevelopmentDependencies:
|
|
14
|
+
Enabled: false
|
|
15
|
+
|
|
16
|
+
SortedMethodsByCall/Waterfall:
|
|
17
|
+
Enabled: true
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2025-11-06 17:49:32 UTC using RuboCop version 1.81.7.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
11
|
+
Metrics/AbcSize:
|
|
12
|
+
Max: 18
|
|
13
|
+
|
|
14
|
+
# Offense count: 4
|
|
15
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
16
|
+
# AllowedMethods: refine
|
|
17
|
+
Metrics/BlockLength:
|
|
18
|
+
Max: 179
|
|
19
|
+
|
|
20
|
+
# Offense count: 3
|
|
21
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
22
|
+
Metrics/MethodLength:
|
|
23
|
+
Max: 18
|
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
6
|
+
|
|
7
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
|
8
|
+
|
|
9
|
+
## Our Standards
|
|
10
|
+
|
|
11
|
+
Examples of behavior that contributes to a positive environment for our community include:
|
|
12
|
+
|
|
13
|
+
* Demonstrating empathy and kindness toward other people
|
|
14
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
15
|
+
* Giving and gracefully accepting constructive feedback
|
|
16
|
+
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
|
17
|
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
|
18
|
+
|
|
19
|
+
Examples of unacceptable behavior include:
|
|
20
|
+
|
|
21
|
+
* The use of sexualized language or imagery, and sexual attention or
|
|
22
|
+
advances of any kind
|
|
23
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
24
|
+
* Public or private harassment
|
|
25
|
+
* Publishing others' private information, such as a physical or email
|
|
26
|
+
address, without their explicit permission
|
|
27
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
28
|
+
professional setting
|
|
29
|
+
|
|
30
|
+
## Enforcement Responsibilities
|
|
31
|
+
|
|
32
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
|
33
|
+
|
|
34
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
35
|
+
|
|
36
|
+
## Scope
|
|
37
|
+
|
|
38
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
|
39
|
+
|
|
40
|
+
## Enforcement
|
|
41
|
+
|
|
42
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at TODO: Write your email address. All complaints will be reviewed and investigated promptly and fairly.
|
|
43
|
+
|
|
44
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
|
45
|
+
|
|
46
|
+
## Enforcement Guidelines
|
|
47
|
+
|
|
48
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
|
49
|
+
|
|
50
|
+
### 1. Correction
|
|
51
|
+
|
|
52
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
|
53
|
+
|
|
54
|
+
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
|
55
|
+
|
|
56
|
+
### 2. Warning
|
|
57
|
+
|
|
58
|
+
**Community Impact**: A violation through a single incident or series of actions.
|
|
59
|
+
|
|
60
|
+
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
|
61
|
+
|
|
62
|
+
### 3. Temporary Ban
|
|
63
|
+
|
|
64
|
+
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
|
65
|
+
|
|
66
|
+
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
|
67
|
+
|
|
68
|
+
### 4. Permanent Ban
|
|
69
|
+
|
|
70
|
+
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
|
71
|
+
|
|
72
|
+
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
|
73
|
+
|
|
74
|
+
## Attribution
|
|
75
|
+
|
|
76
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
|
|
77
|
+
available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
78
|
+
|
|
79
|
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
|
80
|
+
|
|
81
|
+
[homepage]: https://www.contributor-covenant.org
|
|
82
|
+
|
|
83
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
84
|
+
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 unurgunite
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# AdvancedCodeGenerator (ACG)
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://rubygems.org/gems/advanced_code_generator)
|
|
5
|
+
[](https://github.com/unurgunite/advanced_code_generator/actions)
|
|
6
|
+
|
|
7
|
+
**A fluent DSL for generating Ruby classes with stubbed methods for testing and prototyping.**
|
|
8
|
+
|
|
9
|
+
* [AdvancedCodeGenerator (ACG)](#advancedcodegenerator-acg)
|
|
10
|
+
* [Features](#features)
|
|
11
|
+
* [Installation](#installation)
|
|
12
|
+
* [Usage Examples](#usage-examples)
|
|
13
|
+
* [Basic Public Method](#basic-public-method)
|
|
14
|
+
* [Method with Parameters](#method-with-parameters)
|
|
15
|
+
* [Private and Protected Methods](#private-and-protected-methods)
|
|
16
|
+
* [Class Methods](#class-methods)
|
|
17
|
+
* [Random Value Generation](#random-value-generation)
|
|
18
|
+
* [Testing](#testing)
|
|
19
|
+
* [Development](#development)
|
|
20
|
+
* [Available Commands](#available-commands)
|
|
21
|
+
* [Release Process](#release-process)
|
|
22
|
+
* [Requirements](#requirements)
|
|
23
|
+
* [Contributing](#contributing)
|
|
24
|
+
* [License](#license)
|
|
25
|
+
* [Code of Conduct](#code-of-conduct)
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- **Fluent DSL**: Clean, readable syntax for defining methods
|
|
30
|
+
- **Full visibility support**: Public, private, and protected instance methods
|
|
31
|
+
- **Class method support**: Public and private class methods
|
|
32
|
+
- **Parameter configuration**: Define required, optional, and keyword parameters
|
|
33
|
+
- **Smart return values**: Return specific objects or generate random values
|
|
34
|
+
- **Zero dependencies**: Pure Ruby, no external requirements
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
Add this line to your application's Gemfile:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
gem 'advanced_code_generator'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
And then execute:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
bundle install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or install it yourself:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
gem install advanced_code_generator
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage Examples
|
|
57
|
+
|
|
58
|
+
### Basic Public Method
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
generator = AdvancedCodeGenerator::Generator.new do |g|
|
|
62
|
+
g.public_method :hello do |m|
|
|
63
|
+
m.returns "world"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Klass = generator.build
|
|
68
|
+
obj = Klass.new
|
|
69
|
+
obj.hello # => "world"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Method with Parameters
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
generator = AdvancedCodeGenerator::Generator.new do |g|
|
|
76
|
+
g.public_method :greet do |m|
|
|
77
|
+
m.required :name
|
|
78
|
+
m.optional :greeting, default: "Hello"
|
|
79
|
+
m.keyword_required :format
|
|
80
|
+
m.returns true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
Klass = generator.build
|
|
85
|
+
obj = Klass.new
|
|
86
|
+
obj.greet("Alice", format: :json) # => true
|
|
87
|
+
obj.greet("Bob", "Hi", format: :xml) # => true
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Private and Protected Methods
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
generator = AdvancedCodeGenerator::Generator.new do |g|
|
|
94
|
+
g.private_method :secret_calculation do |m|
|
|
95
|
+
m.returns 42
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
g.protected_method :internal_logic do |m|
|
|
99
|
+
m.returns "protected result"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
Klass = generator.build
|
|
104
|
+
obj = Klass.new
|
|
105
|
+
obj.send(:secret_calculation) # => 42
|
|
106
|
+
# obj.secret_calculation # => NoMethodError
|
|
107
|
+
|
|
108
|
+
# Protected method access through subclass
|
|
109
|
+
Subclass = Class.new(Klass) do
|
|
110
|
+
def access_protected
|
|
111
|
+
internal_logic
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
Subclass.new.access_protected # => "protected result"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Class Methods
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
generator = AdvancedCodeGenerator::Generator.new do |g|
|
|
121
|
+
g.public_class_method :factory do |m|
|
|
122
|
+
m.returns "class helper"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
g.private_class_method :setup do |m|
|
|
126
|
+
m.returns "private setup"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
Klass = generator.build
|
|
131
|
+
Klass.factory # => "class helper"
|
|
132
|
+
Klass.send(:setup) # => "private setup"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Random Value Generation
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
generator = AdvancedCodeGenerator::Generator.new do |g|
|
|
139
|
+
g.public_method :random_int do |m|
|
|
140
|
+
m.returns Integer
|
|
141
|
+
m.generate true
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
g.public_method :random_string do |m|
|
|
145
|
+
m.returns String
|
|
146
|
+
m.generate true
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
Klass = generator.build
|
|
151
|
+
obj = Klass.new
|
|
152
|
+
obj.random_int # => 42891 (random integer)
|
|
153
|
+
obj.random_string # => "aB3xY9zK2m" (random string)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Testing
|
|
157
|
+
|
|
158
|
+
Run the test suite:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
bundle exec rspec
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
After checking out the repo, run:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
bin/setup
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
This will install dependencies and start an interactive console.
|
|
173
|
+
|
|
174
|
+
### Available Commands
|
|
175
|
+
|
|
176
|
+
- `bin/console` - Interactive development console
|
|
177
|
+
- `bin/setup` - Install dependencies and build gem
|
|
178
|
+
- `bundle exec rake` - Run tests and linting
|
|
179
|
+
|
|
180
|
+
### Release Process
|
|
181
|
+
|
|
182
|
+
1. Update version in `lib/code_generator/version.rb`
|
|
183
|
+
2. Create and push a git tag: `git tag v0.1.0 && git push origin v0.1.0`
|
|
184
|
+
3. GitHub Actions will automatically:
|
|
185
|
+
- Build the gem
|
|
186
|
+
- Publish to RubyGems.org
|
|
187
|
+
- Create a GitHub release
|
|
188
|
+
|
|
189
|
+
## Requirements
|
|
190
|
+
|
|
191
|
+
- **Ruby**: >= 2.7.0
|
|
192
|
+
- **No external dependencies**
|
|
193
|
+
|
|
194
|
+
## Contributing
|
|
195
|
+
|
|
196
|
+
Bug reports and pull requests are welcome! Please follow these guidelines:
|
|
197
|
+
|
|
198
|
+
1. Fork the repository
|
|
199
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
200
|
+
3. Commit your changes (`git commit -am 'Add amazing feature'`)
|
|
201
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
202
|
+
5. Open a pull request
|
|
203
|
+
|
|
204
|
+
Please ensure your code passes all tests and follows the existing style.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
209
|
+
|
|
210
|
+
## Code of Conduct
|
|
211
|
+
|
|
212
|
+
Everyone interacting with this project is expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
> **Note**: This gem is designed for **testing and prototyping**. Generated methods accept any parameters and return
|
|
217
|
+
> configured values, making it perfect for creating test doubles and stubs.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/advanced_code_generator/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'advanced_code_generator'
|
|
7
|
+
spec.version = AdvancedCodeGenerator::VERSION
|
|
8
|
+
spec.authors = ['unurgunite']
|
|
9
|
+
spec.email = ['senpaiguru1488@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Code generation tool based on preferences.'
|
|
12
|
+
spec.description = <<~TEXT
|
|
13
|
+
This gem makes it possible to generate code based on preferences. You can use it to avoid the boring routine of writing tests, use some classes for other purposes, or just for fun.
|
|
14
|
+
TEXT
|
|
15
|
+
spec.homepage = 'https://github.com/unurgunite/advanced_code_generator.'
|
|
16
|
+
spec.required_ruby_version = '>= 2.7.0'
|
|
17
|
+
|
|
18
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
19
|
+
|
|
20
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
21
|
+
spec.metadata['source_code_uri'] = 'https://github.com/unurgunite/advanced_code_generator'
|
|
22
|
+
spec.metadata['changelog_uri'] = 'https://github.com/unurgunite/advanced_code_generator/CHANGELOG.md'
|
|
23
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
24
|
+
|
|
25
|
+
# Specify which files should be added to the gem when it is released.
|
|
26
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
27
|
+
spec.files = Dir.chdir(__dir__) do
|
|
28
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
29
|
+
(File.expand_path(f) == __FILE__) ||
|
|
30
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
spec.require_paths = ['lib']
|
|
34
|
+
|
|
35
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
36
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
37
|
+
spec.add_development_dependency 'rubocop'
|
|
38
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.24'
|
|
39
|
+
spec.add_development_dependency 'rubocop-sorted_methods_by_call'
|
|
40
|
+
spec.add_development_dependency 'yard'
|
|
41
|
+
|
|
42
|
+
# For more information and examples about making a new gem, check out our
|
|
43
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
|
44
|
+
end
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdvancedCodeGenerator
|
|
4
|
+
# Generates Ruby classes with stubbed methods using a fluent DSL.
|
|
5
|
+
#
|
|
6
|
+
# This class provides a domain-specific language (DSL) for defining
|
|
7
|
+
# methods with various visibility levels, parameters, and return values.
|
|
8
|
+
# It's primarily designed for testing and prototyping scenarios where
|
|
9
|
+
# you need to create mock objects or stub classes quickly.
|
|
10
|
+
#
|
|
11
|
+
# @example Basic usage
|
|
12
|
+
# generator = CodeGenerator::Generator.new do |g|
|
|
13
|
+
# g.public_method :hello do |m|
|
|
14
|
+
# m.returns "world"
|
|
15
|
+
# end
|
|
16
|
+
# end
|
|
17
|
+
# Klass = generator.build
|
|
18
|
+
# obj = Klass.new
|
|
19
|
+
# obj.hello # => "world"
|
|
20
|
+
#
|
|
21
|
+
# @example Method with parameters
|
|
22
|
+
# generator = CodeGenerator::Generator.new do |g|
|
|
23
|
+
# g.public_method :greet do |m|
|
|
24
|
+
# m.required :name
|
|
25
|
+
# m.optional :greeting, default: "Hello"
|
|
26
|
+
# m.returns true
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
class Generator
|
|
30
|
+
# @return [Array<AdvancedCodeGenerator::MethodConfig>] List of instance method configurations
|
|
31
|
+
attr_reader :methods
|
|
32
|
+
|
|
33
|
+
# @return [Array<AdvancedCodeGenerator::MethodConfig>] List of class method configurations
|
|
34
|
+
attr_reader :class_methods
|
|
35
|
+
|
|
36
|
+
# Initializes a new Generator instance with empty method collections.
|
|
37
|
+
#
|
|
38
|
+
# This constructor is typically called internally by {Generator.new}
|
|
39
|
+
# and should not be called directly in most cases.
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
def initialize
|
|
43
|
+
@methods = []
|
|
44
|
+
@class_methods = []
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Creates a new Generator instance and evaluates the given block in its context.
|
|
48
|
+
#
|
|
49
|
+
# This is the primary entry point for using the DSL. The block parameter
|
|
50
|
+
# provides access to the generator's DSL methods for defining methods.
|
|
51
|
+
#
|
|
52
|
+
# @yield [generator] The generator instance for DSL configuration
|
|
53
|
+
# @yieldparam generator [CodeGenerator::Generator] The current generator instance
|
|
54
|
+
# @return [AdvancedCodeGenerator::Generator] A configured generator instance
|
|
55
|
+
#
|
|
56
|
+
# @example
|
|
57
|
+
# generator = CodeGenerator::Generator.new do |g|
|
|
58
|
+
# g.public_method :test_method do |m|
|
|
59
|
+
# m.returns "test"
|
|
60
|
+
# end
|
|
61
|
+
# end
|
|
62
|
+
def self.new(&block)
|
|
63
|
+
generator = allocate
|
|
64
|
+
generator.__send__(:initialize)
|
|
65
|
+
generator.instance_eval(&block) if block
|
|
66
|
+
generator
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Builds and returns a new Ruby class with all configured methods defined.
|
|
70
|
+
#
|
|
71
|
+
# This method creates an anonymous class and defines all the methods
|
|
72
|
+
# that were configured through the DSL. The returned class can be
|
|
73
|
+
# instantiated and used like any other Ruby class.
|
|
74
|
+
#
|
|
75
|
+
# @return [Class] A new class with all configured methods
|
|
76
|
+
#
|
|
77
|
+
# @example
|
|
78
|
+
# generator = CodeGenerator::Generator.new do |g|
|
|
79
|
+
# g.public_method :hello do |m|
|
|
80
|
+
# m.returns "world"
|
|
81
|
+
# end
|
|
82
|
+
# end
|
|
83
|
+
# Klass = generator.build
|
|
84
|
+
# obj = Klass.new
|
|
85
|
+
# puts obj.hello # => "world"
|
|
86
|
+
def build
|
|
87
|
+
klass = Class.new
|
|
88
|
+
define_instance_methods(klass)
|
|
89
|
+
define_class_methods(klass)
|
|
90
|
+
klass
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Defines a public instance method on the generated class.
|
|
94
|
+
#
|
|
95
|
+
# @param name [Symbol, String] The name of the method to define
|
|
96
|
+
# @yield [method_config] Configuration block for the method
|
|
97
|
+
# @yieldparam method_config [CodeGenerator::MethodConfig] Method configuration object
|
|
98
|
+
# @return [void]
|
|
99
|
+
#
|
|
100
|
+
# @example
|
|
101
|
+
# g.public_method :calculate do |m|
|
|
102
|
+
# m.required :x
|
|
103
|
+
# m.optional :y, default: 10
|
|
104
|
+
# m.returns 42
|
|
105
|
+
# end
|
|
106
|
+
def public_method(name, &block)
|
|
107
|
+
method_config = MethodConfig.new(name, :public, &block)
|
|
108
|
+
@methods << method_config
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Defines a private instance method on the generated class.
|
|
112
|
+
#
|
|
113
|
+
# Private methods can only be called within the class or its instances
|
|
114
|
+
# using {Object#send} or from within other instance methods.
|
|
115
|
+
#
|
|
116
|
+
# @param name [Symbol, String] The name of the method to define
|
|
117
|
+
# @yield [method_config] Configuration block for the method
|
|
118
|
+
# @yieldparam method_config [CodeGenerator::MethodConfig] Method configuration object
|
|
119
|
+
# @return [void]
|
|
120
|
+
#
|
|
121
|
+
# @example
|
|
122
|
+
# g.private_method :internal_calculation do |m|
|
|
123
|
+
# m.returns "private result"
|
|
124
|
+
# end
|
|
125
|
+
def private_method(name, &block)
|
|
126
|
+
method_config = MethodConfig.new(name, :private, &block)
|
|
127
|
+
@methods << method_config
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Defines a protected instance method on the generated class.
|
|
131
|
+
#
|
|
132
|
+
# Protected methods can be called by instances of the same class
|
|
133
|
+
# or its subclasses, but not from outside the inheritance hierarchy.
|
|
134
|
+
#
|
|
135
|
+
# @param name [Symbol, String] The name of the method to define
|
|
136
|
+
# @yield [method_config] Configuration block for the method
|
|
137
|
+
# @yieldparam method_config [CodeGenerator::MethodConfig] Method configuration object
|
|
138
|
+
# @return [void]
|
|
139
|
+
#
|
|
140
|
+
# @example
|
|
141
|
+
# g.protected_method :shared_logic do |m|
|
|
142
|
+
# m.returns "protected result"
|
|
143
|
+
# end
|
|
144
|
+
def protected_method(name, &block)
|
|
145
|
+
method_config = MethodConfig.new(name, :protected, &block)
|
|
146
|
+
@methods << method_config
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Defines a public class method on the generated class.
|
|
150
|
+
#
|
|
151
|
+
# Class methods are called on the class itself rather than instances.
|
|
152
|
+
#
|
|
153
|
+
# @param name [Symbol, String] The name of the method to define
|
|
154
|
+
# @yield [method_config] Configuration block for the method
|
|
155
|
+
# @yieldparam method_config [CodeGenerator::MethodConfig] Method configuration object
|
|
156
|
+
# @return [void]
|
|
157
|
+
#
|
|
158
|
+
# @example
|
|
159
|
+
# g.public_class_method :factory do |m|
|
|
160
|
+
# m.returns "class helper"
|
|
161
|
+
# end
|
|
162
|
+
def public_class_method(name, &block)
|
|
163
|
+
method_config = MethodConfig.new(name, :public_class, &block)
|
|
164
|
+
@class_methods << method_config
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Defines a private class method on the generated class.
|
|
168
|
+
#
|
|
169
|
+
# Private class methods can only be called within the class context
|
|
170
|
+
# using {Object#send} on the class itself.
|
|
171
|
+
#
|
|
172
|
+
# @param name [Symbol, String] The name of the method to define
|
|
173
|
+
# @yield [method_config] Configuration block for the method
|
|
174
|
+
# @yieldparam method_config [CodeGenerator::MethodConfig] Method configuration object
|
|
175
|
+
# @return [void]
|
|
176
|
+
#
|
|
177
|
+
# @example
|
|
178
|
+
# g.private_class_method :internal_setup do |m|
|
|
179
|
+
# m.returns "private setup"
|
|
180
|
+
# end
|
|
181
|
+
def private_class_method(name, &block)
|
|
182
|
+
method_config = MethodConfig.new(name, :private_class, &block)
|
|
183
|
+
@class_methods << method_config
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private
|
|
187
|
+
|
|
188
|
+
# Defines all configured instance methods on the target class.
|
|
189
|
+
#
|
|
190
|
+
# @param klass [Class] The class to define methods on
|
|
191
|
+
# @return [void]
|
|
192
|
+
def define_instance_methods(klass)
|
|
193
|
+
return unless @methods
|
|
194
|
+
|
|
195
|
+
@methods.each do |method_config|
|
|
196
|
+
case method_config.visibility
|
|
197
|
+
when :public
|
|
198
|
+
define_method_with_params(klass, method_config, :define_method)
|
|
199
|
+
when :private
|
|
200
|
+
define_method_with_params(klass, method_config, :define_method)
|
|
201
|
+
klass.send(:private, method_config.name)
|
|
202
|
+
when :protected
|
|
203
|
+
define_method_with_params(klass, method_config, :define_method)
|
|
204
|
+
klass.send(:protected, method_config.name)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Defines all configured class methods on the target class.
|
|
210
|
+
#
|
|
211
|
+
# @param klass [Class] The class to define class methods on
|
|
212
|
+
# @return [void]
|
|
213
|
+
def define_class_methods(klass)
|
|
214
|
+
return unless class_methods
|
|
215
|
+
|
|
216
|
+
class_methods.each do |method_config|
|
|
217
|
+
case method_config.visibility
|
|
218
|
+
when :public_class
|
|
219
|
+
define_method_with_params(klass.singleton_class, method_config, :define_method)
|
|
220
|
+
when :private_class
|
|
221
|
+
define_method_with_params(klass.singleton_class, method_config, :define_method)
|
|
222
|
+
klass.singleton_class.send(:private, method_config.name)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Defines a single method on the target class with proper parameter handling.
|
|
228
|
+
#
|
|
229
|
+
# This method handles both simple methods (no parameters) and complex
|
|
230
|
+
# methods (with parameter definitions) by either using define_method
|
|
231
|
+
# with a proc or generating a method definition string with class_eval.
|
|
232
|
+
#
|
|
233
|
+
# @param target_class [Class, #singleton_class] The class to define the method on
|
|
234
|
+
# @param method_config [AdvancedCodeGenerator::MethodConfig] The method configuration
|
|
235
|
+
# @param define_method_name [Symbol] The method used to define methods (:define_method)
|
|
236
|
+
# @return [void]
|
|
237
|
+
def define_method_with_params(target_class, method_config, define_method_name)
|
|
238
|
+
if method_config.parameters.empty?
|
|
239
|
+
return_value = calculate_return_value(method_config)
|
|
240
|
+
target_class.send(define_method_name, method_config.name) do |*_args, **_kwargs|
|
|
241
|
+
return_value
|
|
242
|
+
end
|
|
243
|
+
else
|
|
244
|
+
# Generate actual method with proper parameter validation
|
|
245
|
+
param_string = method_config.parameters.map(&:to_ruby_param).join(', ')
|
|
246
|
+
return_value = calculate_return_value(method_config)
|
|
247
|
+
|
|
248
|
+
# Create the method definition as a string
|
|
249
|
+
method_code = "def #{method_config.name}(#{param_string}); #{return_value.inspect}; end"
|
|
250
|
+
|
|
251
|
+
# Evaluate it in the target class context
|
|
252
|
+
target_class.class_eval(method_code)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Calculates the actual return value for a method configuration.
|
|
257
|
+
#
|
|
258
|
+
# Handles both static return values and random object generation
|
|
259
|
+
# based on the method configuration settings.
|
|
260
|
+
#
|
|
261
|
+
# @param method_config [AdvancedCodeGenerator::MethodConfig] The method configuration
|
|
262
|
+
# @return [Object, nil] The calculated return value
|
|
263
|
+
def calculate_return_value(method_config)
|
|
264
|
+
if method_config.generate_random && method_config.return_value.is_a?(Class)
|
|
265
|
+
generate_random_object(method_config.return_value)
|
|
266
|
+
else
|
|
267
|
+
method_config.return_value
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Generates a random object of the specified class type.
|
|
272
|
+
#
|
|
273
|
+
# Supports Integer, String, and Symbol types with appropriate
|
|
274
|
+
# random generation logic. For unsupported classes, returns
|
|
275
|
+
# the class itself.
|
|
276
|
+
#
|
|
277
|
+
# @param klass [Class] The class to generate a random instance of
|
|
278
|
+
# @return [Object] A random object of the specified type, or the class itself
|
|
279
|
+
#
|
|
280
|
+
# @example
|
|
281
|
+
# generate_random_object(Integer) # => 42891
|
|
282
|
+
# generate_random_object(String) # => "aB3xY9zK2m"
|
|
283
|
+
# generate_random_object(Symbol) # => :random_symbol
|
|
284
|
+
# generate_random_object(Object) # => Object
|
|
285
|
+
def generate_random_object(klass)
|
|
286
|
+
case klass.name
|
|
287
|
+
when 'Integer'
|
|
288
|
+
rand(1..1_000_000)
|
|
289
|
+
when 'String'
|
|
290
|
+
SecureRandom.alphanumeric(10)
|
|
291
|
+
when 'Symbol'
|
|
292
|
+
SecureRandom.alphanumeric(10).to_sym
|
|
293
|
+
else
|
|
294
|
+
klass
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdvancedCodeGenerator
|
|
4
|
+
# Represents the configuration for a single method definition.
|
|
5
|
+
#
|
|
6
|
+
# This class encapsulates all the metadata needed to define a method,
|
|
7
|
+
# including its name, visibility, parameters, return value, and generation
|
|
8
|
+
# settings. It's used internally by {CodeGenerator::Generator} to store
|
|
9
|
+
# method configuration data collected through the DSL.
|
|
10
|
+
#
|
|
11
|
+
# @example Method configuration usage
|
|
12
|
+
# config = CodeGenerator::MethodConfig.new(:calculate, :public) do |m|
|
|
13
|
+
# m.required :x
|
|
14
|
+
# m.optional :y, default: 10
|
|
15
|
+
# m.returns 42
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# @see CodeGenerator::Generator
|
|
19
|
+
# @see CodeGenerator::Parameter
|
|
20
|
+
class MethodConfig
|
|
21
|
+
# @return [Symbol] The name of the method to be defined
|
|
22
|
+
attr_reader :name
|
|
23
|
+
|
|
24
|
+
# @return [Symbol] The visibility level (:public, :private, :protected, :public_class, :private_class)
|
|
25
|
+
attr_reader :visibility
|
|
26
|
+
|
|
27
|
+
# @return [Array<AdvancedCodeGenerator::Parameter>] List of method parameters
|
|
28
|
+
attr_reader :parameters
|
|
29
|
+
|
|
30
|
+
# @return [Object, nil] The value that the method should return
|
|
31
|
+
attr_reader :return_value
|
|
32
|
+
|
|
33
|
+
# @return [Boolean] Whether to generate random values for class return types
|
|
34
|
+
attr_reader :generate_random
|
|
35
|
+
|
|
36
|
+
# Valid visibility options for method definitions.
|
|
37
|
+
#
|
|
38
|
+
# @return [Array<Symbol>]
|
|
39
|
+
VALID_VISIBILITIES = %i[public private protected public_class private_class].freeze
|
|
40
|
+
|
|
41
|
+
# Initializes a new MethodConfig instance.
|
|
42
|
+
#
|
|
43
|
+
# @param name [Symbol, String] The name of the method to configure
|
|
44
|
+
# @param visibility [Symbol] The visibility level (must be one of {VALID_VISIBILITIES})
|
|
45
|
+
# @yield [method_config] Configuration block for method parameters and settings
|
|
46
|
+
# @yieldparam method_config [CodeGenerator::MethodConfig] The current method configuration instance
|
|
47
|
+
# @raise [ArgumentError] If name is not a Symbol/String or visibility is invalid
|
|
48
|
+
#
|
|
49
|
+
# @example
|
|
50
|
+
# config = CodeGenerator::MethodConfig.new(:my_method, :public) do |m|
|
|
51
|
+
# m.required :param1
|
|
52
|
+
# m.returns "result"
|
|
53
|
+
# end
|
|
54
|
+
def initialize(name, visibility)
|
|
55
|
+
raise ArgumentError, 'Method name must be a Symbol or String' unless name.is_a?(Symbol) || name.is_a?(String)
|
|
56
|
+
raise ArgumentError, "Invalid visibility: #{visibility}" unless VALID_VISIBILITIES.include?(visibility)
|
|
57
|
+
|
|
58
|
+
@name = name.to_sym
|
|
59
|
+
@visibility = visibility
|
|
60
|
+
@parameters = []
|
|
61
|
+
@return_value = nil
|
|
62
|
+
@generate_random = false
|
|
63
|
+
|
|
64
|
+
yield self if block_given?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Adds a required positional parameter to the method.
|
|
68
|
+
#
|
|
69
|
+
# Required parameters must be provided when calling the method.
|
|
70
|
+
#
|
|
71
|
+
# @param param_name [Symbol] The name of the required parameter
|
|
72
|
+
# @return [void]
|
|
73
|
+
# @raise [ArgumentError] If param_name is not a Symbol
|
|
74
|
+
#
|
|
75
|
+
# @example
|
|
76
|
+
# m.required :user_id
|
|
77
|
+
# # Generates: def method_name(user_id)
|
|
78
|
+
def required(param_name)
|
|
79
|
+
validate_param_name(param_name)
|
|
80
|
+
parameters << Parameter.new(:required, param_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Adds an optional positional parameter to the method.
|
|
84
|
+
#
|
|
85
|
+
# Optional parameters have a default value and can be omitted when calling the method.
|
|
86
|
+
#
|
|
87
|
+
# @param param_name [Symbol] The name of the optional parameter
|
|
88
|
+
# @param default [Object] The default value for the parameter (defaults to nil)
|
|
89
|
+
# @return [void]
|
|
90
|
+
# @raise [ArgumentError] If param_name is not a Symbol
|
|
91
|
+
#
|
|
92
|
+
# @example
|
|
93
|
+
# m.optional :options, default: {}
|
|
94
|
+
# # Generates: def method_name(options = {})
|
|
95
|
+
def optional(param_name, default: nil)
|
|
96
|
+
validate_param_name(param_name)
|
|
97
|
+
parameters << Parameter.new(:optional, param_name, default: default)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Adds a required keyword parameter to the method.
|
|
101
|
+
#
|
|
102
|
+
# Required keyword parameters must be provided as named arguments when calling the method.
|
|
103
|
+
#
|
|
104
|
+
# @param param_name [Symbol] The name of the required keyword parameter
|
|
105
|
+
# @return [void]
|
|
106
|
+
# @raise [ArgumentError] If param_name is not a Symbol
|
|
107
|
+
#
|
|
108
|
+
# @example
|
|
109
|
+
# m.keyword_required :format
|
|
110
|
+
# # Generates: def method_name(format:)
|
|
111
|
+
def keyword_required(param_name)
|
|
112
|
+
validate_param_name(param_name)
|
|
113
|
+
parameters << Parameter.new(:keyword_required, param_name)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Adds an optional keyword parameter to the method.
|
|
117
|
+
#
|
|
118
|
+
# Optional keyword parameters have a default value and can be omitted when calling the method.
|
|
119
|
+
#
|
|
120
|
+
# @param param_name [Symbol] The name of the optional keyword parameter
|
|
121
|
+
# @param default [Object] The default value for the parameter (defaults to nil)
|
|
122
|
+
# @return [void]
|
|
123
|
+
# @raise [ArgumentError] If param_name is not a Symbol
|
|
124
|
+
#
|
|
125
|
+
# @example
|
|
126
|
+
# m.keyword :timeout, default: 30
|
|
127
|
+
# # Generates: def method_name(timeout: 30)
|
|
128
|
+
def keyword(param_name, default: nil)
|
|
129
|
+
validate_param_name(param_name)
|
|
130
|
+
parameters << Parameter.new(:keyword, param_name, default: default)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Sets the return value for the method.
|
|
134
|
+
#
|
|
135
|
+
# The method will return this value when called. If combined with {#generate},
|
|
136
|
+
# and the return value is a Class, it will generate random instances of that class.
|
|
137
|
+
#
|
|
138
|
+
# @param value [Object] The value to return from the method
|
|
139
|
+
# @return [Object] The provided value
|
|
140
|
+
#
|
|
141
|
+
# @example
|
|
142
|
+
# m.returns "success"
|
|
143
|
+
# m.returns Integer # Will generate random integers if #generate is true
|
|
144
|
+
def returns(value)
|
|
145
|
+
self.return_value = value
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Enables random value generation for class return types.
|
|
149
|
+
#
|
|
150
|
+
# When enabled and the return value is a Class (like Integer, String, Symbol),
|
|
151
|
+
# the method will return random instances of that class instead of the class itself.
|
|
152
|
+
#
|
|
153
|
+
# @param value [Boolean] Whether to enable random generation (defaults to true)
|
|
154
|
+
# @return [Boolean] The provided value
|
|
155
|
+
#
|
|
156
|
+
# @example
|
|
157
|
+
# m.returns Integer
|
|
158
|
+
# m.generate true
|
|
159
|
+
# # Method will return random integers like 42891, not the Integer class
|
|
160
|
+
def generate(value: true)
|
|
161
|
+
self.generate_random = value
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
private
|
|
165
|
+
|
|
166
|
+
# @!attribute [rw] parameters
|
|
167
|
+
# @return [Array<AdvancedCodeGenerator::Parameter>]
|
|
168
|
+
attr_writer :parameters
|
|
169
|
+
|
|
170
|
+
# @!attribute [rw] return_value
|
|
171
|
+
# @return [Object, nil]
|
|
172
|
+
attr_writer :return_value
|
|
173
|
+
|
|
174
|
+
# @!attribute [rw] generate_random
|
|
175
|
+
# @return [Boolean]
|
|
176
|
+
attr_writer :generate_random
|
|
177
|
+
|
|
178
|
+
# Validates that a parameter name is a Symbol.
|
|
179
|
+
#
|
|
180
|
+
# @param name [Object] The parameter name to validate
|
|
181
|
+
# @raise [ArgumentError] If name is not a Symbol
|
|
182
|
+
# @return [void]
|
|
183
|
+
def validate_param_name(name)
|
|
184
|
+
raise ArgumentError, 'Parameter name must be a Symbol' unless name.is_a?(Symbol)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AdvancedCodeGenerator
|
|
4
|
+
# Represents a single method parameter configuration.
|
|
5
|
+
#
|
|
6
|
+
# This class encapsulates the metadata for a method parameter, including
|
|
7
|
+
# its type (required, optional, keyword, etc.), name, and default value.
|
|
8
|
+
# It's used internally by {CodeGenerator::MethodConfig} to store parameter
|
|
9
|
+
# definitions that are later converted to Ruby method signatures.
|
|
10
|
+
#
|
|
11
|
+
# @example Parameter usage
|
|
12
|
+
# param = CodeGenerator::Parameter.new(:required, :user_id)
|
|
13
|
+
# param.to_ruby_param # => "user_id"
|
|
14
|
+
#
|
|
15
|
+
# @see CodeGenerator::MethodConfig
|
|
16
|
+
class Parameter
|
|
17
|
+
# Valid parameter types for method definitions.
|
|
18
|
+
#
|
|
19
|
+
# @return [Array<Symbol>]
|
|
20
|
+
VALID_TYPES = %i[required optional keyword_required keyword].freeze
|
|
21
|
+
|
|
22
|
+
# @return [Symbol] The type of parameter (:required, :optional, :keyword_required, :keyword)
|
|
23
|
+
attr_reader :type
|
|
24
|
+
|
|
25
|
+
# @return [Symbol] The name of the parameter
|
|
26
|
+
attr_reader :name
|
|
27
|
+
|
|
28
|
+
# @return [Object, nil] The default value for optional parameters (nil for required parameters)
|
|
29
|
+
attr_reader :default
|
|
30
|
+
|
|
31
|
+
# Initializes a new Parameter instance.
|
|
32
|
+
#
|
|
33
|
+
# @param type [Symbol] The parameter type (must be one of {VALID_TYPES})
|
|
34
|
+
# @param name [Symbol] The parameter name
|
|
35
|
+
# @param default [Object, nil] The default value for optional parameters (defaults to nil)
|
|
36
|
+
# @raise [ArgumentError] If type is invalid or name is not a Symbol
|
|
37
|
+
#
|
|
38
|
+
# @example
|
|
39
|
+
# # Required parameter
|
|
40
|
+
# param = CodeGenerator::Parameter.new(:required, :id)
|
|
41
|
+
#
|
|
42
|
+
# # Optional parameter with default
|
|
43
|
+
# param = CodeGenerator::Parameter.new(:optional, :options, default: {})
|
|
44
|
+
#
|
|
45
|
+
# # Required keyword parameter
|
|
46
|
+
# param = CodeGenerator::Parameter.new(:keyword_required, :format)
|
|
47
|
+
#
|
|
48
|
+
# # Optional keyword parameter
|
|
49
|
+
# param = CodeGenerator::Parameter.new(:keyword, :timeout, default: 30)
|
|
50
|
+
def initialize(type, name, default: nil)
|
|
51
|
+
raise ArgumentError, "Invalid parameter type: #{type}" unless VALID_TYPES.include?(type)
|
|
52
|
+
raise ArgumentError, 'Parameter name must be a Symbol' unless name.is_a?(Symbol)
|
|
53
|
+
|
|
54
|
+
@type = type
|
|
55
|
+
@name = name
|
|
56
|
+
@default = default
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Converts the parameter configuration to a Ruby method parameter string.
|
|
60
|
+
#
|
|
61
|
+
# This method generates the appropriate Ruby syntax for the parameter
|
|
62
|
+
# based on its type and configuration, which is used when defining
|
|
63
|
+
# methods with {CodeGenerator::Generator}.
|
|
64
|
+
#
|
|
65
|
+
# @return [String] The Ruby parameter string
|
|
66
|
+
#
|
|
67
|
+
# @example
|
|
68
|
+
# CodeGenerator::Parameter.new(:required, :name).to_ruby_param
|
|
69
|
+
# # => "name"
|
|
70
|
+
#
|
|
71
|
+
# CodeGenerator::Parameter.new(:optional, :options, default: {}).to_ruby_param
|
|
72
|
+
# # => "options = {}"
|
|
73
|
+
#
|
|
74
|
+
# CodeGenerator::Parameter.new(:keyword_required, :format).to_ruby_param
|
|
75
|
+
# # => "format:"
|
|
76
|
+
#
|
|
77
|
+
# CodeGenerator::Parameter.new(:keyword, :timeout, default: 30).to_ruby_param
|
|
78
|
+
# # => "timeout: 30"
|
|
79
|
+
def to_ruby_param
|
|
80
|
+
case type
|
|
81
|
+
when :required
|
|
82
|
+
name.to_s
|
|
83
|
+
when :optional
|
|
84
|
+
if default.nil?
|
|
85
|
+
"#{name} = nil"
|
|
86
|
+
else
|
|
87
|
+
"#{name} = #{default.inspect}"
|
|
88
|
+
end
|
|
89
|
+
when :keyword_required
|
|
90
|
+
"#{name}:"
|
|
91
|
+
when :keyword
|
|
92
|
+
if default.nil?
|
|
93
|
+
"#{name}: nil"
|
|
94
|
+
else
|
|
95
|
+
"#{name}: #{default.inspect}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Returns the parameter name as a Symbol.
|
|
101
|
+
#
|
|
102
|
+
# This is a convenience method that simply returns the {#name} attribute.
|
|
103
|
+
#
|
|
104
|
+
# @return [Symbol] The parameter name
|
|
105
|
+
#
|
|
106
|
+
# @example
|
|
107
|
+
# param = CodeGenerator::Parameter.new(:required, :user_id)
|
|
108
|
+
# param.ruby_param_name # => :user_id
|
|
109
|
+
def ruby_param_name
|
|
110
|
+
name
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require_relative 'advanced_code_generator/version'
|
|
5
|
+
require_relative 'advanced_code_generator/parameter'
|
|
6
|
+
require_relative 'advanced_code_generator/method_config'
|
|
7
|
+
require_relative 'advanced_code_generator/generator'
|
|
8
|
+
|
|
9
|
+
module AdvancedCodeGenerator
|
|
10
|
+
class Error < StandardError; end
|
|
11
|
+
end
|
data/rakelib/docs.rake
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'English'
|
|
4
|
+
require 'yard'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
|
|
7
|
+
GEM_NAME = Bundler.load_gemspec(Dir.glob('*.gemspec').first).name
|
|
8
|
+
DOCS_REPO_NAME = "#{GEM_NAME}_docs"
|
|
9
|
+
DOCS_REPO_PATH = "../#{DOCS_REPO_NAME}"
|
|
10
|
+
|
|
11
|
+
namespace :docs do
|
|
12
|
+
desc 'Generate new docs and push them to repo'
|
|
13
|
+
task generate: :clean do
|
|
14
|
+
puts 'Generating docs...'
|
|
15
|
+
YARD::CLI::Yardoc.run
|
|
16
|
+
puts 'OK!'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc 'Clean existing docs'
|
|
20
|
+
task :clean do
|
|
21
|
+
if File.directory?('doc')
|
|
22
|
+
FileUtils.rm_rf('doc')
|
|
23
|
+
puts 'Cleaned existing docs directory'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc 'Pushes docs to github'
|
|
28
|
+
task push: :generate do
|
|
29
|
+
unless File.directory?(DOCS_REPO_PATH)
|
|
30
|
+
puts "Error: Docs repo not found at #{DOCS_REPO_PATH}"
|
|
31
|
+
puts 'Please clone the docs repo first:'
|
|
32
|
+
puts " git clone git@github.com:unurgunite/#{DOCS_REPO_NAME}.git #{DOCS_REPO_PATH}"
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
puts "Copying docs to #{DOCS_REPO_PATH}..."
|
|
37
|
+
FileUtils.mkdir_p('doc') unless File.directory?('doc')
|
|
38
|
+
FileUtils.cp_r('doc/.', DOCS_REPO_PATH)
|
|
39
|
+
|
|
40
|
+
puts 'Changing dir...'
|
|
41
|
+
Dir.chdir(DOCS_REPO_PATH) do
|
|
42
|
+
puts 'Checking git status...'
|
|
43
|
+
status_output = `git status --porcelain`
|
|
44
|
+
|
|
45
|
+
if status_output.strip.empty?
|
|
46
|
+
puts 'No changes to commit'
|
|
47
|
+
else
|
|
48
|
+
puts 'Committing git changes...'
|
|
49
|
+
puts `git add .`
|
|
50
|
+
commit_result = `git commit -m "Update docs for #{GEM_NAME} #{Time.now.utc.strftime('%Y-%m-%d %H:%M:%S UTC')}"`
|
|
51
|
+
puts commit_result
|
|
52
|
+
|
|
53
|
+
if $CHILD_STATUS.success?
|
|
54
|
+
puts 'Pushing to GitHub...'
|
|
55
|
+
push_result = `git push origin master 2>&1`
|
|
56
|
+
puts push_result
|
|
57
|
+
if $CHILD_STATUS.success?
|
|
58
|
+
puts 'Docs successfully pushed!'
|
|
59
|
+
else
|
|
60
|
+
puts 'Push failed!'
|
|
61
|
+
exit 1
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
puts 'Commit failed!'
|
|
65
|
+
exit 1
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
desc 'Generate and push docs in one command'
|
|
72
|
+
task deploy: :push
|
|
73
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: advanced_code_generator
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- unurgunite
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rake
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '13.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '13.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rspec
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rubocop
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rubocop-rspec
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '2.24'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '2.24'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rubocop-sorted_methods_by_call
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: yard
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
description: 'This gem makes it possible to generate code based on preferences. You
|
|
97
|
+
can use it to avoid the boring routine of writing tests, use some classes for other
|
|
98
|
+
purposes, or just for fun.
|
|
99
|
+
|
|
100
|
+
'
|
|
101
|
+
email:
|
|
102
|
+
- senpaiguru1488@gmail.com
|
|
103
|
+
executables: []
|
|
104
|
+
extensions: []
|
|
105
|
+
extra_rdoc_files: []
|
|
106
|
+
files:
|
|
107
|
+
- ".rspec"
|
|
108
|
+
- ".rubocop.yml"
|
|
109
|
+
- ".rubocop_todo.yml"
|
|
110
|
+
- CHANGELOG.md
|
|
111
|
+
- CODE_OF_CONDUCT.md
|
|
112
|
+
- LICENSE.txt
|
|
113
|
+
- README.md
|
|
114
|
+
- Rakefile
|
|
115
|
+
- code_generator.gemspec
|
|
116
|
+
- lib/advanced_code_generator.rb
|
|
117
|
+
- lib/advanced_code_generator/generator.rb
|
|
118
|
+
- lib/advanced_code_generator/method_config.rb
|
|
119
|
+
- lib/advanced_code_generator/parameter.rb
|
|
120
|
+
- lib/advanced_code_generator/version.rb
|
|
121
|
+
- rakelib/docs.rake
|
|
122
|
+
homepage: https://github.com/unurgunite/advanced_code_generator.
|
|
123
|
+
licenses: []
|
|
124
|
+
metadata:
|
|
125
|
+
allowed_push_host: https://rubygems.org
|
|
126
|
+
homepage_uri: https://github.com/unurgunite/advanced_code_generator.
|
|
127
|
+
source_code_uri: https://github.com/unurgunite/advanced_code_generator
|
|
128
|
+
changelog_uri: https://github.com/unurgunite/advanced_code_generator/CHANGELOG.md
|
|
129
|
+
rubygems_mfa_required: 'true'
|
|
130
|
+
rdoc_options: []
|
|
131
|
+
require_paths:
|
|
132
|
+
- lib
|
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: 2.7.0
|
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
|
+
requirements:
|
|
140
|
+
- - ">="
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: '0'
|
|
143
|
+
requirements: []
|
|
144
|
+
rubygems_version: 3.7.2
|
|
145
|
+
specification_version: 4
|
|
146
|
+
summary: Code generation tool based on preferences.
|
|
147
|
+
test_files: []
|