omochi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9a34b2f4942b833cad4251d39b655591949025be459aa5433e352ec5daa467cd
4
+ data.tar.gz: 381bd6ca1e03d74e26e76773d1a9d61c14c0521f6b026230a4558652e9984d10
5
+ SHA512:
6
+ metadata.gz: 582c88432f47a69d2822f92f1b8a4ccd4c3c1bae42f072bb2fa85d296d7ec6cc613f8451781f5d59b449b66b43e3a13a08cca2b036a96650666be934e69bd1c0
7
+ data.tar.gz: 5d1515d85ac400cf4b029bd04e0082b6bb48c8273e47028786e4e7b9f231b3652ecd50d026f2b774acad6991192ebe8344a6333f4e20b3a27fe2b328fb043d49
data/DESIGN.md ADDED
@@ -0,0 +1,7 @@
1
+ This library has 5 major steps.
2
+
3
+ 1. Fetch Ruby files from diffs, including spec files
4
+ 2. Parse them to AST
5
+ 3. Get all methods and spec `describe`s and compare
6
+ 4. If every method is covered, successfully return, otherwise print their names
7
+ 5. If `--create` option is given, generate skeletons for missing specs
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in omochi.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Hashino Mikiko
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,189 @@
1
+ # Omochi
2
+
3
+ Omochi is a CLI tool to support Ruby on Rails development with RSpec. It detects methods uncovered by tests and prints the test code generated by LLM.
4
+
5
+ There are two advantages of using Omochi. We can make sure every method is covered by tests with GitHub Actions support. We can also generate spec files for uncovered methods so that we can reduce time to write them manually.
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ $ gem specific_install -l https://github.com/mikik0/omochi.git
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```
16
+ $ omochi --help
17
+ Commands:
18
+ omochi help [COMMAND] # Describe available commands or one specific command
19
+ omochi verify local_path # verify spec created for all of new methods and functions
20
+ ```
21
+
22
+ ## Commands
23
+ ### verify
24
+
25
+ When you execute Omochi locally, you can confirm that you have spec coverage for uncommitted diff.
26
+
27
+ ```
28
+ # Local
29
+ $ omochi verify local_path
30
+ ```
31
+
32
+ You can skip check with ignore comment.
33
+
34
+ ```ruby
35
+ #omochi:ignore:
36
+ ```
37
+
38
+ ### --create option
39
+
40
+ You can generate spec files with LLM by giving `-c` or `--create` option. It outputs to STDOUT.
41
+
42
+ ```
43
+ # Generate spec files
44
+ $ omochi verify local_path -c
45
+ # Or
46
+ $ omochi verify local_path --create
47
+ ```
48
+
49
+ ### --github option
50
+
51
+ With `-h` option you can check uncovered methods against given Pull Request with GitHub Actions.
52
+ It uses `gh pr diff` command internally.
53
+
54
+ ```
55
+ $ omochi verify local_path -h
56
+ # Or
57
+ $ omochi verify local_path --github
58
+ ```
59
+
60
+ ## Samples
61
+
62
+ ```
63
+ $ omochi verify -c
64
+ "Verify File List: [\"lib/omochi/cli.rb\", \"lib/omochi/util.rb\"]"
65
+ "specファイルあり"
66
+ "There are spec files."
67
+ ===================================================================
68
+ verifyのテストを以下に表示します。
69
+ We will show the test of verify below.
70
+ require 'rspec'
71
+
72
+ describe 'exit_on_failure?' do
73
+ it 'returns true' do
74
+ expect(exit_on_failure?).to eq(true)
75
+ end
76
+ end
77
+ ======= RESULT: lib/omochi/cli.rb =======
78
+ - exit_on_failure?
79
+ "specファイルなし"
80
+ ======= RESULT: lib/omochi/util.rb =======
81
+ - local_diff_path
82
+ - github_diff_path
83
+ - remote_diff_path
84
+ - get_ast
85
+ - dfs
86
+ - find_spec_file
87
+ - get_pure_function_name
88
+ - dfs_describe
89
+ - print_result
90
+ - get_ignore_methods
91
+ - create_spec_by_bedrock
92
+ ===================================================================
93
+ lib/omochi/util.rbのテストを以下に表示します。
94
+ We will show the test of lib/omochi/util.rb below.
95
+ require "spec_helper"
96
+
97
+ describe "local_diff_path" do
98
+ it "returns array of diff paths from git" do
99
+ allow(Open3).to receive(:capture3).with("git diff --name-only", any_args).and_return(["path1", "path2"], "", double(success?: true))
100
+ expect(local_diff_path).to eq(["path1", "path2"])
101
+ end
102
+
103
+ it "returns empty array if git command fails" do
104
+ allow(Open3).to receive(:capture3).with("git diff --name-only", any_args).and_return("", "error", double(success?: false))
105
+ expect(local_diff_path).to eq([])
106
+ end
107
+ end
108
+
109
+ describe "github_diff_path" do
110
+ it "returns array of diff paths from gh" do
111
+ allow(Open3).to receive(:capture3).with("gh pr diff --name-only", any_args).and_return(["path1", "path2"], "", double(success?: true))
112
+ expect(github_diff_path).to eq(["path1", "path2"])
113
+ end
114
+
115
+ it "returns empty array if gh command fails" do
116
+ allow(Open3).to receive(:capture3).with("gh pr diff --name-only", any_args).and_return("", "error", double(success?: false))
117
+ expect(github_diff_path).to eq([])
118
+ end
119
+ end
120
+
121
+ describe "remote_diff_path" do
122
+ it "returns array of diff paths from remote" do
123
+ allow(Open3).to receive(:capture3).with(/git diff --name-only .*${{ github\.sha }}/, any_args).and_return(["path1", "path2"], "", double(success?: true))
124
+ expect(remote_diff_path).to eq(["path1", "path2"])
125
+ end
126
+
127
+ it "returns empty array if git command fails" do
128
+ allow(Open3).to receive(:capture3).with(/git diff --name-only .*${{ github\.sha }}/, any_args).and_return("", "error", double(success?: false))
129
+ expect(remote_diff_path).to eq([])
130
+ end
131
+ end
132
+
133
+ describe "get_ast" do
134
+ it "returns AST for given file" do
135
+ allow(File).to receive(:read).with("file.rb").and_return("code")
136
+ allow(Parser::CurrentRuby).to receive(:parse_with_comments).with("code").and_return(["ast"], ["comments"])
137
+ expect(get_ast("file.rb")).to eq([{ast: "ast", filename: "file.rb"}])
138
+ end
139
+ end
140
+
141
+ describe "dfs" do
142
+ let(:node) { double(:node, type: :def, children: [double(:child, children: ["name"])]) }
143
+ let(:result) { {} }
144
+
145
+ it "traverses node and captures def names" do
146
+ dfs(node, "file.rb", result)
147
+ expect(result).to eq({"name" => "def name\nend"})
148
+ end
149
+ end
150
+
151
+ describe "find_spec_file" do
152
+ before do
153
+ allow(File).to receive(:exist?).with("spec/app/file_spec.rb").and_return(true)
154
+ end
155
+
156
+ it "returns spec file path if exists" do
157
+ expect(find_spec_file("app/file.rb")).to eq("spec/app/file_spec.rb")
158
+ end
159
+
160
+ it "returns nil if spec file does not exist" do
161
+ allow(File).to receive(:exist?).with("spec/app/file_spec.rb").and_return(false)
162
+ expect(find_spec_file("app/file.rb")).to be_nil
163
+ end
164
+ end
165
+
166
+ # similarly test other functions
167
+ ```
168
+
169
+ ## Contributing
170
+
171
+ Bug reports and Pull Requests are accepted on GitHub (https://github.com/mikik0/omochi).
172
+ This project should be a safe place for collaboration.
173
+
174
+ ### Design
175
+
176
+ See [DESIGN.md](https://github.com/mikik0/omochi/blob/master/DESIGN.md)
177
+
178
+ ### Development
179
+
180
+ #### Requirement
181
+
182
+ - ruby3.x
183
+ - AWS Credentials (for `--create`)
184
+
185
+ ```
186
+ git clone https://github.com/mikik0/omochi.git
187
+ bundle install
188
+ bundle exec bin/omochi verify
189
+ ```
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ task default: %i[]
data/exe/omochi ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'omochi'
4
+
5
+ Omochi::CLI.start
data/lib/omochi/cli.rb ADDED
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'omochi'
4
+ require 'thor'
5
+ require 'omochi/util'
6
+ require 'yaml'
7
+ require 'aws-sdk-bedrockruntime'
8
+ require 'dotenv/load'
9
+ require 'unparser'
10
+
11
+ module Omochi
12
+ class CLI < Thor
13
+ include Omochi::Util
14
+
15
+ class << self
16
+ def exit_on_failure?
17
+ true
18
+ end
19
+ end
20
+
21
+ desc 'verify local_path', 'verify spec created for all of new methods and functions'
22
+ method_option :github, aliases: '-h', desc: 'Running on GitHub Action'
23
+ method_option :create, aliases: '-c', desc: 'Create Spec for Untested Method'
24
+ def verify
25
+ is_gh_action = options[:github] == 'github'
26
+ is_gl_ci_runner = false
27
+ create_spec = options[:create] == 'create'
28
+ perfect = true
29
+
30
+ diff_paths = case [is_gh_action, is_gl_ci_runner]
31
+ when [true, false]
32
+ github_diff_path
33
+ when [false, true]
34
+ remote_diff_path
35
+ when [false, false]
36
+ local_diff_path
37
+ end
38
+
39
+ # Ruby 以外のファイル(yamlやmdなど)を除外 specファイルも除外(テストにはテストない)
40
+ diff_paths.reject! { |s| !s.end_with?('.rb') || s.end_with?('_spec.rb') }
41
+ p "Verify File List: #{diff_paths}"
42
+
43
+ # diff_paths 例: ["lib/omochi/cli.rb", "lib/omochi/util.rb"]
44
+ diff_paths.each do |diff_path|
45
+ if find_spec_file(diff_path)
46
+ p 'specファイルあり'
47
+ p 'There are spec files.'
48
+ perfect = process_spec_file(diff_path, create_spec, perfect)
49
+ else
50
+ p 'specファイルなし'
51
+ p 'There is no spec file.'
52
+ perfect = process_missing_spec_file(diff_path, create_spec, perfect)
53
+ end
54
+ end
55
+ exit(perfect ? 0 : 1)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,257 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'parser/current'
5
+ require 'json'
6
+ require 'nokogiri'
7
+
8
+ module Omochi
9
+ module Util
10
+ include AST::Processor::Mixin
11
+
12
+ def local_diff_path
13
+ # Gitがインストールされているか確認
14
+ unless system('git --version > /dev/null 2>&1')
15
+ puts 'Error: Git is not installed. Please install Git.'
16
+ return []
17
+ end
18
+
19
+ # ローカルのdiffを取得する
20
+ diff_command = 'git diff --diff-filter=d --name-only'
21
+ diff_output, _diff_error, _diff_status = Open3.capture3(diff_command, chdir: '.')
22
+
23
+ # エラーチェック
24
+ unless _diff_status.success?
25
+ puts "Error: Failed to run 'git diff' command."
26
+ return []
27
+ end
28
+
29
+ # 取得したdiffのpathを返却する
30
+ diff_output.split("\n")
31
+ end
32
+
33
+ def github_diff_path
34
+ diff_command = 'gh pr diff --name-only'
35
+ diff_output, _diff_error, _diff_status = Open3.capture3(diff_command, chdir: '.')
36
+
37
+ # エラーチェック
38
+ unless _diff_status.success?
39
+ puts "Error: Failed to run 'gh pr diff' command."
40
+ return []
41
+ end
42
+ # 取得したdiffのpathを返却する
43
+ diff_output.split("\n")
44
+ end
45
+
46
+ def remote_diff_path
47
+ # リモートのdiffを取得する
48
+ diff_command = 'git diff --name-only origin/${{ github.event.pull_request.base.ref }}..${{ github.sha }}'
49
+ diff_output, _diff_error, _diff_status = Open3.capture3(diff_command, chdir: '.')
50
+
51
+ # エラーチェック
52
+ unless _diff_status.success?
53
+ puts "Error: Failed to run 'git diff' command."
54
+ return []
55
+ end
56
+
57
+ # 取得したdiffのpathを返却する
58
+ diff_output.split("\n")
59
+ end
60
+
61
+ def find_spec_file(diff_path)
62
+ spec_path = File.join('spec', diff_path.gsub(/\.rb$/, '_spec.rb').gsub('app/', ''))
63
+ File.exist?(spec_path) ? spec_path : nil
64
+ end
65
+
66
+ def process_spec_file(diff_path, create_spec, perfect)
67
+ # 対応するSpecファイルが存在した場合のロジック
68
+ result = {}
69
+ spec_def_name_arr = []
70
+ spec_file_path = find_spec_file(diff_path)
71
+ # スペックファイルがあれば、specfileの中身を確認していく。
72
+ # defメソッド名だけ切り出す {:call => {code}, :verify => {code}, ....}
73
+ # ASTを再帰的に探索し、メソッド名とコードを取得
74
+ get_ast(diff_path).each do |expr|
75
+ dfs(expr[:ast], expr[:filename], result)
76
+ end
77
+ result = result.transform_keys(&:to_s)
78
+ # describeメソッド [call]
79
+ # []の中にastが入る
80
+ get_ast(spec_file_path).each do |expr|
81
+ spec_def_name_arr = dfs_describe(expr[:ast], expr[:filename], spec_def_name_arr)
82
+ end
83
+
84
+ # resultのHashでSpecが存在するものをTrueに更新
85
+ spec_def_name_arr.each do |spec_def_name|
86
+ next unless result.key?(spec_def_name)
87
+
88
+ result[spec_def_name] = true
89
+
90
+ next unless create_spec
91
+
92
+ method_code = result[spec_def_name]
93
+ puts '==================================================================='
94
+ puts "#{spec_def_name} のテストを以下に表示します。"
95
+ puts "We will show the test of #{spec_def_name} below."
96
+ create_spec_by_bedrock(method_code)
97
+ end
98
+
99
+ get_ignore_methods(diff_path).each do |def_name|
100
+ result[def_name] = true if result.key?(def_name)
101
+ end
102
+
103
+ return perfect = false if print_result(diff_path, result).size > 0
104
+ end
105
+
106
+ def process_missing_spec_file(diff_path, create_spec, perfect)
107
+ # 対応するSpecファイルが存在しない場合のロジック
108
+ result = {}
109
+ ignored_def_names = get_ignore_methods(diff_path)
110
+ get_ast(diff_path).each do |expr|
111
+ dfs(expr[:ast], expr[:filename], result)
112
+ end
113
+ result = result.transform_keys(&:to_s)
114
+
115
+ ignored_def_names.each do |def_name|
116
+ result[def_name] = true if result.key?(def_name)
117
+ end
118
+
119
+ if create_spec
120
+ # exprs[0] の AST からメソッド内のコードを生成
121
+ ast_code = get_ast(diff_path)[0][:ast]
122
+ method_code = Unparser.unparse(ast_code)
123
+
124
+ puts '==================================================================='
125
+ puts "#{diff_path} のテストを以下に表示します。"
126
+ puts "We will show the test of #{diff_path} below."
127
+ create_spec_by_bedrock(method_code)
128
+ end
129
+ return perfect = false if print_result(diff_path, result).size > 0
130
+ end
131
+
132
+ private
133
+
134
+ def get_ast(diff_path)
135
+ exprs = []
136
+ ast = Parser::CurrentRuby.parse(File.read(diff_path))
137
+ exprs << { ast: ast, filename: diff_path }
138
+ end
139
+
140
+ def dfs(node, filename, result)
141
+ return unless node.is_a?(Parser::AST::Node)
142
+
143
+ # ノードの種類に応じて処理を実行
144
+ case node.type
145
+ when :def
146
+ # :def ノードの場合、メソッド定義に関する処理を実行
147
+ # ファイル名とメソッド名をつめてます。
148
+ child_value = node.children[0]
149
+ code = Unparser.unparse(node)
150
+ result[child_value] = code
151
+ end
152
+
153
+ # 子ノードに対して再帰的に深さ優先探索
154
+ node.children.each { |child| dfs(child, filename, result) }
155
+ end
156
+
157
+ # rspecのdescribeでは、通常 # または . の直後に関数名を書くため
158
+ def get_pure_function_name(str)
159
+ if str.start_with?('#', '.')
160
+ str[1..-1] # 2番目以降の文字列を返す
161
+ else
162
+ str # 変更が不要な場合はそのまま返す
163
+ end
164
+ end
165
+
166
+ def dfs_describe(node, filename, def_name_arr)
167
+ return unless node.is_a?(Parser::AST::Node)
168
+
169
+ # ノードの種類に応じて処理を実行
170
+ case node.type
171
+ when :send
172
+ method_node = node.children[1]
173
+ if node.children[1] == :describe
174
+ def_name = node.children[2].children[0] # "Omochi::CLI"
175
+ if !def_name.nil? && def_name.is_a?(String)
176
+ def_name = get_pure_function_name(def_name)
177
+ def_name_arr.push(def_name)
178
+ end
179
+ end
180
+ end
181
+
182
+ # 子ノードに対して再帰的に深さ優先探索
183
+ node.children.each { |child| dfs_describe(child, filename, def_name_arr) }
184
+ def_name_arr
185
+ end
186
+
187
+ def print_result(filename, result)
188
+ puts "\e[31m======= RESULT: #{filename} =======\e[0m"
189
+ method_list = result.reject { |_key, value| value == true }.keys
190
+ method_list.each do |file|
191
+ puts "- \e[32m#{file}\e[0m"
192
+ end
193
+
194
+ method_list
195
+ end
196
+
197
+ def get_ignore_methods(diff_path)
198
+ ignore_methods = []
199
+ code = File.open(diff_path, 'r').read
200
+ lines = code.split("\n")
201
+ ignore_next_function = false
202
+
203
+ lines.each do |line|
204
+ if line.match(/omochi:ignore:*/) && line.strip.start_with?('#')
205
+ ignore_next_function = true
206
+ next
207
+ end
208
+
209
+ if ignore_next_function && line.match(/\s*def\s+(\w+)/)
210
+ ignore_methods << Regexp.last_match(1)
211
+ ignore_next_function = false
212
+ end
213
+ end
214
+
215
+ ignore_methods
216
+ end
217
+
218
+ def create_spec_by_bedrock(code)
219
+ # 必要な関数だけ渡すのと比較する。
220
+ bedrock_client = Aws::BedrockRuntime::Client.new(region: 'us-east-1')
221
+ comment = "You are a brilliant Ruby programmer.
222
+ You have been assigned to a project to automate QA testing for a system.
223
+ Please write the Ruby function you want to test inside the <code> XML tags.
224
+ Write the tests using RSpec to cover all branches of the function comprehensively.
225
+ Include many test cases to thoroughly verify the function.
226
+ You must output the test code inside the <test> XML tags absolutely.
227
+ Do not include any content besides the test code. <code> #{code} </code>"
228
+ body_data = {
229
+ "anthropic_version": 'bedrock-2023-05-31',
230
+ "max_tokens": 4000,
231
+ "temperature": 0.0,
232
+ "messages": [
233
+ {
234
+ "role": 'user',
235
+ "content": "#{comment}"
236
+ }
237
+ ]
238
+ }
239
+ response = bedrock_client.invoke_model({
240
+ accept: '*/*',
241
+ content_type: 'application/json',
242
+ body: body_data.to_json,
243
+ model_id: 'anthropic.claude-3-sonnet-20240229-v1:0'
244
+ })
245
+
246
+ string_io_object = response.body
247
+ data = JSON.parse(string_io_object.string)
248
+ code_html = data['content'][0]['text']
249
+
250
+ # nokogiri を使用して HTML を解析し、<test> タグの中身を取得
251
+ doc = Nokogiri::HTML(code_html)
252
+ code_content = doc.at('test').content.strip
253
+
254
+ puts code_content
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omochi
4
+ VERSION = '0.1.0'
5
+ end
data/lib/omochi.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'omochi/version'
2
+ require_relative 'omochi/cli'
3
+
4
+ module Omochi
5
+ end
data/sig/omochi.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Omochi
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omochi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - mikiko.hashino
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-07-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-bedrockruntime
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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: parser
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: thor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: unparser
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Omochi is a CLI tool to support Ruby on Rails development with RSpec.
112
+ email:
113
+ - mikko.1222.u@gmail.com
114
+ executables:
115
+ - omochi
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - DESIGN.md
120
+ - Gemfile
121
+ - LICENSE
122
+ - README.md
123
+ - Rakefile
124
+ - exe/omochi
125
+ - lib/omochi.rb
126
+ - lib/omochi/cli.rb
127
+ - lib/omochi/util.rb
128
+ - lib/omochi/version.rb
129
+ - sig/omochi.rbs
130
+ homepage: https://github.com/mikik0/omochi
131
+ licenses:
132
+ - MIT
133
+ metadata:
134
+ homepage_uri: https://github.com/mikik0/omochi
135
+ source_code_uri: https://github.com/mikik0/omochi
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 2.6.0
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.5.11
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: Omochi is a CLI tool to support Ruby on Rails development with RSpec.
155
+ test_files: []