ai_refactor 0.4.0 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 725fb1da5fc311d3740687d97fa3b6c3c4292a3b531f467ea1d8ff9e734608bc
4
- data.tar.gz: 4c16d310c643ae1158442816a9f863961ae151bb4ae486c965e96340342e2d44
3
+ metadata.gz: e50d610e50fdbccc133cd5951cee61244602b402917aa2eb1ab37713b3a6b276
4
+ data.tar.gz: eee461b016a3dec20476828383da3571999649097472eedc68f736d6ea759057
5
5
  SHA512:
6
- metadata.gz: d0f380ef54a29be017b23c2caaa4491ee6304dc410e52ab6e11038b9f30c30a09a04597f3342332f464007e0e932f5b81112f712d46c584b2728d51bee61c036
7
- data.tar.gz: 9ffa29857815cb73daef7d6902bf7301dc80e36361b0451d3d3df1b7921b1c0978ef16ea7963c544b893db1bd0d6db34120378aa6a7ae4ac5add0831e4b61dbf
6
+ metadata.gz: c4c913a3263949687e98681697e5fe2631748aa57dbc3ea4c7aa3f367a3ce98cb6d2d3ea86653f2e949fd65d055dd9c0f67d93c79602742fb179a27568639ed6
7
+ data.tar.gz: 41324b5dd54d62f59d749638c7b813e4d2fcc4d75528aaf4e37ba4027773b87195a1dad6ffc4400b9ce34ba38004319d7385879b8d01f00a8161a86eec842a6a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # AI Refactor Changelog
2
2
 
3
+ ## [0.5.1] - 2023-09-21
4
+
5
+ ### Added
6
+
7
+ - Support for substitutions in path templates.
8
+
9
+ ### Fixed
10
+
11
+ - Fixes issue with refactor type specified on command line not being picked up.
12
+
13
+
14
+ ## [0.5.0] - 2023-09-21
15
+
16
+ ### Added
17
+
18
+ - Support for new command files, which are YAML files that can be used to define options for a refactor. This makes it
19
+ simpler to create configurations for refactors that will be used repeatedly. They can be committed to source control
20
+ of your project and shared with other developers.
21
+ - Support for configuring the run commands for the test runners
22
+ - Adding real life examples
23
+
3
24
  ## [0.4.0] - 2023-08-15
4
25
 
5
26
  ### Added
data/Gemfile CHANGED
@@ -12,3 +12,10 @@ gem "minitest", "~> 5.0"
12
12
  gem "standard", "~> 1.3"
13
13
 
14
14
  gem "dotenv"
15
+
16
+ # for the examples
17
+
18
+ gem "rails"
19
+ gem "rspec"
20
+ gem "rspec-rails"
21
+ gem "shoulda-matchers"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ai_refactor (0.4.0)
4
+ ai_refactor (0.5.1)
5
5
  colorize (< 2.0)
6
6
  open3 (< 2.0)
7
7
  ruby-openai (>= 3.4.0, < 5.0)
@@ -10,28 +10,179 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
+ actioncable (7.0.8)
14
+ actionpack (= 7.0.8)
15
+ activesupport (= 7.0.8)
16
+ nio4r (~> 2.0)
17
+ websocket-driver (>= 0.6.1)
18
+ actionmailbox (7.0.8)
19
+ actionpack (= 7.0.8)
20
+ activejob (= 7.0.8)
21
+ activerecord (= 7.0.8)
22
+ activestorage (= 7.0.8)
23
+ activesupport (= 7.0.8)
24
+ mail (>= 2.7.1)
25
+ net-imap
26
+ net-pop
27
+ net-smtp
28
+ actionmailer (7.0.8)
29
+ actionpack (= 7.0.8)
30
+ actionview (= 7.0.8)
31
+ activejob (= 7.0.8)
32
+ activesupport (= 7.0.8)
33
+ mail (~> 2.5, >= 2.5.4)
34
+ net-imap
35
+ net-pop
36
+ net-smtp
37
+ rails-dom-testing (~> 2.0)
38
+ actionpack (7.0.8)
39
+ actionview (= 7.0.8)
40
+ activesupport (= 7.0.8)
41
+ rack (~> 2.0, >= 2.2.4)
42
+ rack-test (>= 0.6.3)
43
+ rails-dom-testing (~> 2.0)
44
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
45
+ actiontext (7.0.8)
46
+ actionpack (= 7.0.8)
47
+ activerecord (= 7.0.8)
48
+ activestorage (= 7.0.8)
49
+ activesupport (= 7.0.8)
50
+ globalid (>= 0.6.0)
51
+ nokogiri (>= 1.8.5)
52
+ actionview (7.0.8)
53
+ activesupport (= 7.0.8)
54
+ builder (~> 3.1)
55
+ erubi (~> 1.4)
56
+ rails-dom-testing (~> 2.0)
57
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
58
+ activejob (7.0.8)
59
+ activesupport (= 7.0.8)
60
+ globalid (>= 0.3.6)
61
+ activemodel (7.0.8)
62
+ activesupport (= 7.0.8)
63
+ activerecord (7.0.8)
64
+ activemodel (= 7.0.8)
65
+ activesupport (= 7.0.8)
66
+ activestorage (7.0.8)
67
+ actionpack (= 7.0.8)
68
+ activejob (= 7.0.8)
69
+ activerecord (= 7.0.8)
70
+ activesupport (= 7.0.8)
71
+ marcel (~> 1.0)
72
+ mini_mime (>= 1.1.0)
73
+ activesupport (7.0.8)
74
+ concurrent-ruby (~> 1.0, >= 1.0.2)
75
+ i18n (>= 1.6, < 2)
76
+ minitest (>= 5.1)
77
+ tzinfo (~> 2.0)
13
78
  ast (2.4.2)
79
+ builder (3.2.4)
14
80
  colorize (0.8.1)
81
+ concurrent-ruby (1.2.2)
82
+ crass (1.0.6)
83
+ date (3.3.3)
84
+ diff-lcs (1.5.0)
15
85
  dotenv (2.8.1)
86
+ erubi (1.12.0)
16
87
  faraday (2.7.4)
17
88
  faraday-net_http (>= 2.0, < 3.1)
18
89
  ruby2_keywords (>= 0.0.4)
19
90
  faraday-multipart (1.0.4)
20
91
  multipart-post (~> 2)
21
92
  faraday-net_http (3.0.2)
93
+ globalid (1.2.1)
94
+ activesupport (>= 6.1)
95
+ i18n (1.14.1)
96
+ concurrent-ruby (~> 1.0)
22
97
  json (2.6.3)
23
98
  language_server-protocol (3.17.0.3)
24
99
  lint_roller (1.0.0)
100
+ loofah (2.21.3)
101
+ crass (~> 1.0.2)
102
+ nokogiri (>= 1.12.0)
103
+ mail (2.8.1)
104
+ mini_mime (>= 0.1.1)
105
+ net-imap
106
+ net-pop
107
+ net-smtp
108
+ marcel (1.0.2)
109
+ method_source (1.0.0)
110
+ mini_mime (1.1.5)
25
111
  minitest (5.18.0)
26
112
  multipart-post (2.3.0)
113
+ net-imap (0.3.7)
114
+ date
115
+ net-protocol
116
+ net-pop (0.1.2)
117
+ net-protocol
118
+ net-protocol (0.2.1)
119
+ timeout
120
+ net-smtp (0.3.3)
121
+ net-protocol
122
+ nio4r (2.5.9)
123
+ nokogiri (1.15.4-arm64-darwin)
124
+ racc (~> 1.4)
27
125
  open3 (0.1.2)
28
126
  parallel (1.23.0)
29
127
  parser (3.2.2.1)
30
128
  ast (~> 2.4.1)
129
+ racc (1.7.1)
130
+ rack (2.2.8)
131
+ rack-test (2.1.0)
132
+ rack (>= 1.3)
133
+ rails (7.0.8)
134
+ actioncable (= 7.0.8)
135
+ actionmailbox (= 7.0.8)
136
+ actionmailer (= 7.0.8)
137
+ actionpack (= 7.0.8)
138
+ actiontext (= 7.0.8)
139
+ actionview (= 7.0.8)
140
+ activejob (= 7.0.8)
141
+ activemodel (= 7.0.8)
142
+ activerecord (= 7.0.8)
143
+ activestorage (= 7.0.8)
144
+ activesupport (= 7.0.8)
145
+ bundler (>= 1.15.0)
146
+ railties (= 7.0.8)
147
+ rails-dom-testing (2.2.0)
148
+ activesupport (>= 5.0.0)
149
+ minitest
150
+ nokogiri (>= 1.6)
151
+ rails-html-sanitizer (1.6.0)
152
+ loofah (~> 2.21)
153
+ nokogiri (~> 1.14)
154
+ railties (7.0.8)
155
+ actionpack (= 7.0.8)
156
+ activesupport (= 7.0.8)
157
+ method_source
158
+ rake (>= 12.2)
159
+ thor (~> 1.0)
160
+ zeitwerk (~> 2.5)
31
161
  rainbow (3.1.1)
32
162
  rake (13.0.6)
33
163
  regexp_parser (2.8.0)
34
164
  rexml (3.2.5)
165
+ rspec (3.12.0)
166
+ rspec-core (~> 3.12.0)
167
+ rspec-expectations (~> 3.12.0)
168
+ rspec-mocks (~> 3.12.0)
169
+ rspec-core (3.12.2)
170
+ rspec-support (~> 3.12.0)
171
+ rspec-expectations (3.12.3)
172
+ diff-lcs (>= 1.2.0, < 2.0)
173
+ rspec-support (~> 3.12.0)
174
+ rspec-mocks (3.12.6)
175
+ diff-lcs (>= 1.2.0, < 2.0)
176
+ rspec-support (~> 3.12.0)
177
+ rspec-rails (6.0.3)
178
+ actionpack (>= 6.1)
179
+ activesupport (>= 6.1)
180
+ railties (>= 6.1)
181
+ rspec-core (~> 3.12)
182
+ rspec-expectations (~> 3.12)
183
+ rspec-mocks (~> 3.12)
184
+ rspec-support (~> 3.12)
185
+ rspec-support (3.12.1)
35
186
  rubocop (1.50.2)
36
187
  json (~> 2.3)
37
188
  parallel (~> 1.10)
@@ -52,6 +203,8 @@ GEM
52
203
  faraday-multipart (>= 1)
53
204
  ruby-progressbar (1.13.0)
54
205
  ruby2_keywords (0.0.5)
206
+ shoulda-matchers (5.3.0)
207
+ activesupport (>= 5.2.0)
55
208
  standard (1.28.2)
56
209
  language_server-protocol (~> 3.17.0.2)
57
210
  lint_roller (~> 1.0)
@@ -63,7 +216,14 @@ GEM
63
216
  standard-performance (1.0.1)
64
217
  lint_roller (~> 1.0)
65
218
  rubocop-performance (~> 1.16.0)
219
+ thor (1.2.2)
220
+ timeout (0.4.0)
221
+ tzinfo (2.0.6)
222
+ concurrent-ruby (~> 1.0)
66
223
  unicode-display_width (2.4.2)
224
+ websocket-driver (0.7.6)
225
+ websocket-extensions (>= 0.1.0)
226
+ websocket-extensions (0.1.5)
67
227
  zeitwerk (2.6.8)
68
228
 
69
229
  PLATFORMS
@@ -73,7 +233,11 @@ DEPENDENCIES
73
233
  ai_refactor!
74
234
  dotenv
75
235
  minitest (~> 5.0)
236
+ rails
76
237
  rake (~> 13.0)
238
+ rspec
239
+ rspec-rails
240
+ shoulda-matchers
77
241
  standard (~> 1.3)
78
242
 
79
243
  BUNDLED WITH
data/README.md CHANGED
@@ -1,22 +1,75 @@
1
- # AI Refactor for Ruby
1
+ # AIRefactor for Ruby
2
2
 
3
- AI Refactor is an experimental tool to use AI to help apply refactoring to code.
3
+ __The goal for AIRefactor is to use LLMs to apply repetitive refactoring tasks to code.__
4
4
 
5
- __The goal for AI Refactor is to help apply repetitive refactoring tasks, not to replace human mind that decides what refactoring is needed.__
5
+ First the human decides what refactoring is needed and builds up a prompt to describe the task, or uses one of AIRefactors provided prompts.
6
+
7
+ AIRefactor then helps to apply the refactoring to one or more files.
8
+
9
+ In some cases, the tool can then check the generated code by running tests and comparing test outputs.
10
+
11
+ #### Notes
12
+
13
+ AI Refactor is an experimental tool and under active development as I explore the idea myself. It may not work as expected, or
14
+ change in ways that break existing functionality.
15
+
16
+ The focus of the tool is work with the Ruby programming language ecosystem, but it can be used with any language.
6
17
 
7
18
  AI Refactor currently uses [OpenAI's ChatGPT](https://platform.openai.com/).
8
19
 
9
- The tool lets the human user prompt the AI with explicit refactoring tasks, and can be run on one or more files at a time.
10
- The tool then uses a LLM to apply the relevant refactor, and if appropriate, checks results by running tests and comparing output.
20
+ ## Examples
21
+
22
+ See the [examples](examples/) directory for some examples of using the tool.
23
+
24
+ You can run the command files to run the example.
25
+
26
+ For example, the first example can be run with: (you can add options if desired, eg `-v` for verbose output and `-d` for debug output)
27
+
28
+ ```shell
29
+ ./exe/ai_refactor examples/ex1_convert_a_rspec_test_to_minitest.yml
30
+ ```
31
+
32
+ You should see:
33
+
34
+ ```
35
+ $ ./exe/ai_refactor examples/ex1_convert_a_rspec_test_to_minitest.yml
36
+ Loading refactor command file 'examples/ex1_convert_a_rspec_test_to_minitest.yml'...
37
+ AI Refactor 1 files(s)/dir(s) '["examples/ex1_input_spec.rb"]' with rails/minitest/rspec_to_minitest refactor
38
+ ====================
39
+ Processing examples/ex1_input_spec.rb...
40
+
41
+ No differences found! Conversion worked!
42
+ Refactor succeeded on examples/ex1_input_spec.rb
43
+
44
+ All files processed successfully!
45
+ Done processing all files!
46
+ ```
47
+
48
+ And find the file `examples/ex1_input_test.rb` has been created. Note the process above also ran the generated test file and compared the output to the original test file.
49
+
50
+ If you see an error, then try to run it again, or use a different GPT model.
11
51
 
12
- The focus of the tool is work with the Ruby programming language ecosystem, but it can be used with any language.
13
52
 
14
53
  ## Available refactors
15
54
 
16
- Currently available:
55
+ Write your own prompt:
56
+
57
+ - `ruby/write_ruby`: provide your own prompt for the AI and expect to output Ruby code (no input files required)
58
+ - `ruby/refactor_ruby`: provide your own refactoring prompt for the AI and expect to output Ruby code
59
+ - `custom`: provide your own prompt for the AI and run against the input files. There is no expectation of the output.
17
60
 
61
+ Use a pre-built prompt:
62
+
63
+ - `minitest/write_test_for_class`: write a minitest test for a given class
18
64
  - `rails/minitest/rspec_to_minitest`: convert RSpec specs to minitest tests in Rails apps
19
- - `generic`: provide your own prompt for the AI and run against the input files
65
+
66
+ ### User supplied prompts, eg `custom`, `ruby/write_ruby` and `ruby/refactor_ruby`
67
+
68
+ Applies the refactor specified by prompting the AI with the user supplied prompt. You must supply a prompt file with the `-p` option.
69
+
70
+ The output is written to `stdout`, or to a file with the `--output` option.
71
+
72
+ User supplied prompts are best configured using a command file, see below.
20
73
 
21
74
  ### `rails/minitest/rspec_to_minitest`
22
75
 
@@ -44,12 +97,6 @@ Refactor succeeded on spec/models/my_thing_spec.rb
44
97
  Done processing all files!
45
98
  ```
46
99
 
47
- ### `generic` (user supplied prompt)
48
-
49
- Applies the refactor specified by prompting the AI with the user supplied prompt. You must supply a prompt file with the `-p` option.
50
-
51
- The output is written to `stdout`, or to a file with the `--output` option.
52
-
53
100
  ### `minitest/write_test_for_class`
54
101
 
55
102
  Writes a minitest test for a given class. The output will, by default, be put into a directory named `test` in the current directory,
@@ -75,13 +122,14 @@ If bundler is not being used to manage dependencies, install the gem by executin
75
122
  See `ai_refactor --help` for more information.
76
123
 
77
124
  ```
78
- Usage: ai_refactor REFACTOR_TYPE INPUT_FILE_OR_DIR [options]
125
+ Usage: ai_refactor REFACTOR_TYPE_OR_COMMAND_FILE INPUT_FILE_OR_DIR [options]
79
126
 
80
- Where REFACTOR_TYPE is one of: ["generic" ... (run ai_refactor --help for full list of refactor types)]
127
+ Where REFACTOR_TYPE_OR_COMMAND_FILE is either the path to a command YML file, or one of the refactor types: ["custom" ... (run ai_refactor --help for full list of refactor types)]
81
128
 
82
129
  -o, --output [FILE] Write output to given file instead of stdout. If no path provided will overwrite input file (will prompt to overwrite existing files). Some refactor tasks will write out to a new file by default. This option will override the tasks default behaviour.
83
130
  -O, --output-template TEMPLATE Write outputs to files instead of stdout. The template is used to create the output name, where the it can have substitutions, '[FILE]', '[NAME]', '[DIR]', '[REFACTOR]' & '[EXT]'. Eg `[DIR]/[NAME]_[REFACTOR][EXT]` (will prompt to overwrite existing files)
84
131
  -c, --context CONTEXT_FILES Specify one or more files to use as context for the AI. The contents of these files will be prepended to the prompt sent to the AI.
132
+ -x, --extra CONTEXT_TEXT Specify some text to be prepended to the prompt sent to the AI as extra information of note.
85
133
  -r, --review-prompt Show the prompt that will be sent to ChatGPT but do not actually call ChatGPT or make changes to files.
86
134
  -p, --prompt PROMPT_FILE Specify path to a text file that contains the ChatGPT 'system' prompt.
87
135
  -f, --diffs Request AI generate diffs of changes rather than writing out the whole file.
@@ -91,11 +139,81 @@ Where REFACTOR_TYPE is one of: ["generic" ... (run ai_refactor --help for full l
91
139
  --max-tokens MAX_TOKENS Specify the max number of tokens of output ChatGPT can generate. Max will depend on the size of the prompt (default 1500)
92
140
  -t, --timeout SECONDS Specify the max wait time for ChatGPT response.
93
141
  --overwrite ANSWER Always overwrite existing output files, 'y' for yes, 'n' for no, or 'a' for ask. Default to ask.
142
+ -N, --no Never overwrite existing output files, same as --overwrite=n.
94
143
  -v, --verbose Show extra output and progress info
95
144
  -d, --debug Show debugging output to help diagnose issues
96
145
  -h, --help Prints this help
97
146
  ```
98
147
 
148
+ ### Interactive mode
149
+
150
+ A basic interactive mode exists too, where you are prompted for options.
151
+
152
+ Start interactive mode by not specifying anything for `REFACTOR_TYPE_OR_COMMAND_FILE` (ie no refactor type or command file)
153
+
154
+ ### Command files and Custom prompts
155
+
156
+ Apart from invoking the tool with CLI options, the tool can also be invoked with a command file.
157
+
158
+ This makes it easier to build custom refactor prompts for projects, and run that custom refactor multiple times.
159
+
160
+ The command file is a YAML file that contains configuration options to pass to the tool.
161
+
162
+ The format of the YAML file is:
163
+
164
+ ```yaml
165
+ # Required options:
166
+ refactor: refactor type name, eg 'ruby/write_ruby'
167
+ # Optional options:
168
+ input_file_paths:
169
+ - input files or directories
170
+ output_file_path: output file or directory
171
+ output_template_path: output file template (see docs)
172
+ prompt_file_path: path
173
+ prompt: |
174
+ A custom prompt to send to ChatGPT if the command needs it (otherwise read from file)
175
+ context_file_paths:
176
+ - file1.rb
177
+ - file2.rb
178
+ # Other configuration options:
179
+ context_text: |
180
+ Some extra info to prepend to the prompt
181
+ diff: true/false (default false)
182
+ ai_max_attempts: max times to generate more if AI does not complete generating (default 3)
183
+ ai_model: ChatGPT model name (default gpt-4)
184
+ ai_temperature: ChatGPT temperature (default 0.7)
185
+ ai_max_tokens: ChatGPT max tokens (default 1500)
186
+ ai_timeout: ChatGPT timeout (default 60)
187
+ overwrite: y/n/a (default a)
188
+ verbose: true/false (default false)
189
+ debug: true/false (default false)
190
+ ```
191
+
192
+ The command file can be invoked by passing it as the first argument to the tool:
193
+
194
+ ```shell
195
+ ai_refactor my_command_file.yml
196
+ ```
197
+
198
+ Other options can be passed on the command line and will override the options in the command file.
199
+
200
+ For example, if the command file contains:
201
+
202
+ ```shell
203
+ ai_refactor my_command_file.yml my_input.rb -d --output foo.rb
204
+ ```
205
+
206
+ ### Prompt template substitutions
207
+
208
+ Prompt text can contain the following substitutions:
209
+
210
+ * `__{{input_file_path}}__`: the path to the input file
211
+ * `__{{output_file_path}}__`: the path to the output file
212
+ * `__{{prompt_header}}__`: the place the pre-build prompt will be injected, if used
213
+ * `__{{prompt_footer}}__`: prompt text that will be inserted after the prompt, eg the "make diffs" prompt if `--diffs` is used
214
+ * `__{{context}}__`: the contents of the context files, if any
215
+ * `__{{content}}__`: the contents of input file, if any
216
+
99
217
  ## Outputs
100
218
 
101
219
  Some refactor tasks will write out to a new file by default, others to stdout.
@@ -117,6 +235,17 @@ eg for the input `my_dir/my_class.rb`
117
235
  - `[REFACTOR]`: `generic`
118
236
  - `[EXT]`: `.rb`
119
237
 
238
+ ## Configuration
239
+
240
+ ### `.ai_refactor` file
241
+
242
+ The tool can be configured using a `.ai_refactor` file in the current directory or in the user's home directory.
243
+
244
+ This file provides default CLI switches to add to any `ai_refactor` command.
245
+
246
+ ## Command history
247
+
248
+ The tool keeps a history of commands run in the `.ai_refactor_history` file in the current working directory.
120
249
 
121
250
  ## Note on performance and ChatGPT version
122
251
 
@@ -0,0 +1 @@
1
+ ex1_input_test.rb
@@ -0,0 +1,7 @@
1
+ refactor: rails/minitest/rspec_to_minitest
2
+ input_file_paths:
3
+ - examples/ex1_input_spec.rb
4
+ # We need to add context here as otherwise to tell the AI to require our local test_helper.rb file so that we can run the tests after
5
+ context_text: "In the output test use `require_relative` to include 'test_helper'."
6
+ # By default, ai_refactor runs "bundle exec rails test" but this isn't going to work here as we are not actually in a Rails app context in the examples
7
+ minitest_run_command: ruby __FILE__
@@ -0,0 +1,32 @@
1
+ require_relative "rails_helper"
2
+
3
+ RSpec.describe MyModel, type: :model do
4
+ subject(:model) { described_class.new }
5
+
6
+ it { is_expected.to validate_presence_of(:name) }
7
+
8
+ it "should allow integer values for age" do
9
+ model.age = 1
10
+ expect(model.age).to eq 1
11
+ end
12
+
13
+ it "should allow string values for name" do
14
+ model.name = "test"
15
+ expect(model.name).to eq "test"
16
+ end
17
+
18
+ it "should be invalid with invalid name" do
19
+ model.name = nil
20
+ expect(model).to be_invalid
21
+ end
22
+
23
+ it "should convert integer values for name" do
24
+ model.name = 1
25
+ expect(model.name).to eq "1"
26
+ end
27
+
28
+ it "should not allow string values for age" do
29
+ model.age = "test"
30
+ expect(model.age).to eq 0
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ require "rails/all"
2
+ require "shoulda-matchers"
3
+
4
+ Shoulda::Matchers.configure do |config|
5
+ config.integrate do |with|
6
+ with.test_framework :rspec
7
+ with.library :rails
8
+ end
9
+ end
10
+
11
+ class MyModel
12
+ include ActiveModel::Model
13
+ include ActiveModel::Attributes
14
+ include ActiveModel::Validations
15
+ include ActiveModel::Validations::Callbacks
16
+
17
+ validates :name, presence: true
18
+
19
+ attribute :name, :string
20
+ attribute :age, :integer
21
+ end
@@ -0,0 +1,14 @@
1
+ require "rails/all"
2
+ require "active_support/testing/autorun"
3
+
4
+ class MyModel
5
+ include ActiveModel::Model
6
+ include ActiveModel::Attributes
7
+ include ActiveModel::Validations
8
+ include ActiveModel::Validations::Callbacks
9
+
10
+ validates :name, presence: true
11
+
12
+ attribute :name, :string
13
+ attribute :age, :integer
14
+ end