├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── rspec-kickstarter ├── lib ├── rspec_kickstarter.rb └── rspec_kickstarter │ ├── erb_factory.rb │ ├── erb_templates.rb │ ├── generator.rb │ ├── rdoc_factory.rb │ └── version.rb ├── rspec-kickstarter ├── rspec-kickstarter.gemspec ├── samples ├── delta_template.erb └── full_template.erb └── spec ├── rspec_kickstarter ├── generator_spec.rb ├── rdoc_factory_spec.rb └── version_spec.rb ├── rspec_kickstarter_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .idea 4 | .bundle 5 | .config 6 | .yardoc 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | # Include gemspec and Rakefile 3 | Include: 4 | - '**/*.rb' 5 | Exclude: 6 | - 'bin/**/*' 7 | - 'tmp/**/*' 8 | - 'vendor/**/*' 9 | - 'Guardfile' 10 | RunRailsCops: true 11 | 12 | AsciiComments: 13 | Enabled: false 14 | 15 | Metrics/ClassLength: 16 | Max: 200 17 | 18 | Metrics/CyclomaticComplexity: 19 | Max: 8 20 | 21 | Metrics/LineLength: 22 | Max: 120 23 | 24 | Metrics/MethodLength: 25 | Max: 80 26 | 27 | Style/AsciiComments: 28 | Enabled: false 29 | 30 | Style/Blocks: 31 | Enabled: false 32 | 33 | # Respect RubyMine formatter 34 | Style/CaseIndentation: 35 | Enabled: false 36 | 37 | Style/Documentation: 38 | Enabled: false 39 | 40 | Style/DotPosition: 41 | EnforcedStyle: trailing 42 | 43 | Style/GuardClause: 44 | Enabled: false 45 | 46 | Style/IfUnlessModifier: 47 | Enabled: false 48 | 49 | # Name reduce block params |a, e|. 50 | Style/SingleLineBlockParams: 51 | Enabled: false 52 | 53 | # Respect RubyMine formatter 54 | Style/SpaceInsideHashLiteralBraces: 55 | Enabled: false 56 | 57 | # Cannot deal with AR#eager_load 58 | Style/SymbolProc: 59 | Enabled: false 60 | 61 | # Final newline missing. 62 | Style/TrailingBlankLines: 63 | Enabled: false 64 | 65 | TrivialAccessors: 66 | Enabled: true 67 | ExactNameMatch: true 68 | 69 | Style/SpaceInsideBlockBraces: 70 | Enabled: false 71 | 72 | Style/MultilineBlockChain: 73 | Enabled: false 74 | 75 | Style/NumericLiterals: 76 | Enabled: false 77 | 78 | Style/AlignArray: 79 | Enabled: false 80 | 81 | # Do not prefix writer method names with set_ 82 | Style/AccessorMethodName: 83 | Enabled: false 84 | 85 | Rails/Output: 86 | Enabled: false 87 | 88 | Style/MultilineOperationIndentation: 89 | Enabled: false 90 | 91 | Style/EmptyLinesAroundClassBody: 92 | Enabled: false 93 | 94 | Style/EmptyLinesAroundBlockBody: 95 | Enabled: false 96 | 97 | Style/EmptyLinesAroundModuleBody: 98 | Enabled: false 99 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0.0 4 | - 2.1.8 5 | - 2.2.4 6 | - 2.3.0 7 | script: bundle exec rspec spec 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rspec' 4 | 5 | gem 'simplecov', require: false 6 | gem 'coveralls', require: false 7 | gem 'guard', require: false 8 | gem 'guard-rspec', require: false 9 | gem 'guard-rubocop', require: false 10 | 11 | gemspec 12 | 13 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | rspec-kickstarter (1.0.2) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | ast (2.2.0) 10 | astrolabe (1.3.1) 11 | parser (~> 2.2) 12 | coderay (1.1.0) 13 | coveralls (0.8.10) 14 | json (~> 1.8) 15 | rest-client (>= 1.6.8, < 2) 16 | simplecov (~> 0.11.0) 17 | term-ansicolor (~> 1.3) 18 | thor (~> 0.19.1) 19 | tins (~> 1.6.0) 20 | diff-lcs (1.2.5) 21 | docile (1.1.5) 22 | domain_name (0.5.25) 23 | unf (>= 0.0.5, < 1.0.0) 24 | ffi (1.9.10) 25 | ffi (1.9.10-java) 26 | formatador (0.2.5) 27 | guard (2.13.0) 28 | formatador (>= 0.2.4) 29 | listen (>= 2.7, <= 4.0) 30 | lumberjack (~> 1.0) 31 | nenv (~> 0.1) 32 | notiffany (~> 0.0) 33 | pry (>= 0.9.12) 34 | shellany (~> 0.0) 35 | thor (>= 0.18.1) 36 | guard-compat (1.2.1) 37 | guard-rspec (4.6.4) 38 | guard (~> 2.1) 39 | guard-compat (~> 1.1) 40 | rspec (>= 2.99.0, < 4.0) 41 | guard-rubocop (1.2.0) 42 | guard (~> 2.0) 43 | rubocop (~> 0.20) 44 | http-cookie (1.0.2) 45 | domain_name (~> 0.5) 46 | json (1.8.3) 47 | json (1.8.3-java) 48 | listen (3.0.5) 49 | rb-fsevent (>= 0.9.3) 50 | rb-inotify (>= 0.9) 51 | lumberjack (1.0.10) 52 | method_source (0.8.2) 53 | mime-types (2.99) 54 | nenv (0.2.0) 55 | netrc (0.11.0) 56 | notiffany (0.0.8) 57 | nenv (~> 0.1) 58 | shellany (~> 0.0) 59 | parser (2.2.3.0) 60 | ast (>= 1.1, < 3.0) 61 | powerpack (0.1.1) 62 | pry (0.10.3) 63 | coderay (~> 1.1.0) 64 | method_source (~> 0.8.1) 65 | slop (~> 3.4) 66 | pry (0.10.3-java) 67 | coderay (~> 1.1.0) 68 | method_source (~> 0.8.1) 69 | slop (~> 3.4) 70 | spoon (~> 0.0) 71 | rainbow (2.0.0) 72 | rb-fsevent (0.9.7) 73 | rb-inotify (0.9.5) 74 | ffi (>= 0.5.0) 75 | rest-client (1.8.0) 76 | http-cookie (>= 1.0.2, < 2.0) 77 | mime-types (>= 1.16, < 3.0) 78 | netrc (~> 0.7) 79 | rspec (3.4.0) 80 | rspec-core (~> 3.4.0) 81 | rspec-expectations (~> 3.4.0) 82 | rspec-mocks (~> 3.4.0) 83 | rspec-core (3.4.1) 84 | rspec-support (~> 3.4.0) 85 | rspec-expectations (3.4.0) 86 | diff-lcs (>= 1.2.0, < 2.0) 87 | rspec-support (~> 3.4.0) 88 | rspec-mocks (3.4.0) 89 | diff-lcs (>= 1.2.0, < 2.0) 90 | rspec-support (~> 3.4.0) 91 | rspec-support (3.4.1) 92 | rubocop (0.35.1) 93 | astrolabe (~> 1.3) 94 | parser (>= 2.2.3.0, < 3.0) 95 | powerpack (~> 0.1) 96 | rainbow (>= 1.99.1, < 3.0) 97 | ruby-progressbar (~> 1.7) 98 | tins (<= 1.6.0) 99 | ruby-progressbar (1.7.5) 100 | shellany (0.0.1) 101 | simplecov (0.11.1) 102 | docile (~> 1.1.0) 103 | json (~> 1.8) 104 | simplecov-html (~> 0.10.0) 105 | simplecov-html (0.10.0) 106 | slop (3.6.0) 107 | spoon (0.0.4) 108 | ffi 109 | term-ansicolor (1.3.2) 110 | tins (~> 1.0) 111 | thor (0.19.1) 112 | tins (1.6.0) 113 | unf (0.1.4) 114 | unf_ext 115 | unf (0.1.4-java) 116 | unf_ext (0.0.7.1) 117 | 118 | PLATFORMS 119 | java 120 | ruby 121 | 122 | DEPENDENCIES 123 | coveralls 124 | guard 125 | guard-rspec 126 | guard-rubocop 127 | rspec 128 | rspec-kickstarter! 129 | simplecov 130 | 131 | BUNDLED WITH 132 | 1.11.2 133 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | ## Uncomment and set this to only include directories you want to watch 5 | # directories %w(app lib config test spec feature) 6 | 7 | ## Uncomment to clear the screen before every task 8 | # clearing :on 9 | 10 | ## Make Guard exit when config is changed so it can be restarted 11 | # 12 | ## Note: if you want Guard to automatically start up again, run guard in a 13 | ## shell loop, e.g.: 14 | # 15 | # $ while bundle exec guard; do echo "Restarting Guard..."; done 16 | # 17 | ## Note: if you are using the `directories` clause above and you are not 18 | ## watching the project directory ('.'), the you will want to move the Guardfile 19 | ## to a watched dir and symlink it back, e.g. 20 | # 21 | # $ mkdir config 22 | # $ mv Guardfile config/ 23 | # $ ln -s config/Guardfile . 24 | # 25 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile" 26 | # 27 | watch ("Guardfile") do 28 | UI.info "Exiting because Guard must be restarted for changes to take effect" 29 | exit 0 30 | end 31 | 32 | guard :rubocop do 33 | watch(%r{.+\.rb$}) 34 | watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) } 35 | end 36 | 37 | # Note: The cmd option is now required due to the increasing number of ways 38 | # rspec may be run, below are examples of the most common uses. 39 | # * bundler: 'bundle exec rspec' 40 | # * bundler binstubs: 'bin/rspec' 41 | # * spring: 'bin/rspec' (This will use spring if running and you have 42 | # installed the spring binstubs per the docs) 43 | # * zeus: 'zeus rspec' (requires the server to be started separately) 44 | # * 'just' rspec: 'rspec' 45 | 46 | guard :rspec, cmd: "bundle exec rspec" do 47 | require "guard/rspec/dsl" 48 | dsl = Guard::RSpec::Dsl.new(self) 49 | 50 | # Feel free to open issues for suggestions and improvements 51 | 52 | # RSpec files 53 | rspec = dsl.rspec 54 | watch(rspec.spec_helper) { rspec.spec_dir } 55 | watch(rspec.spec_support) { rspec.spec_dir } 56 | watch(rspec.spec_files) 57 | 58 | # Ruby files 59 | ruby = dsl.ruby 60 | dsl.watch_spec_files_for(ruby.lib_files) 61 | 62 | # Rails files 63 | rails = dsl.rails(view_extensions: %w(erb haml slim)) 64 | dsl.watch_spec_files_for(rails.app_files) 65 | dsl.watch_spec_files_for(rails.views) 66 | 67 | watch(rails.controllers) do |m| 68 | [ 69 | rspec.spec.("routing/#{m[1]}_routing"), 70 | rspec.spec.("controllers/#{m[1]}_controller"), 71 | rspec.spec.("acceptance/#{m[1]}") 72 | ] 73 | end 74 | 75 | # Rails config changes 76 | watch(rails.spec_helper) { rspec.spec_dir } 77 | watch(rails.routes) { "#{rspec.spec_dir}/routing" } 78 | watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } 79 | 80 | # Capybara features specs 81 | watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") } 82 | 83 | # Turnip features and steps 84 | watch(%r{^spec/acceptance/(.+)\.feature$}) 85 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| 86 | Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance" 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 - Kazuhiro Sera 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rspec-kickstarter 2 | 3 | RSpec 3 code generator toward existing Ruby code. This gem will help you working on existing legacy code which has no tests. 4 | 5 | [![Build Status](https://travis-ci.org/seratch/rspec-kickstarter.png)](https://travis-ci.org/seratch/rspec-kickstarter) 6 | [![Coverage Status](https://coveralls.io/repos/seratch/rspec-kickstarter/badge.png)](https://coveralls.io/r/seratch/rspec-kickstarter) 7 | [![Code Climate](https://codeclimate.com/github/seratch/rspec-kickstarter.png)](https://codeclimate.com/github/seratch/rspec-kickstarter) 8 | 9 | ## Installation 10 | 11 | https://rubygems.org/gems/rspec-kickstarter 12 | 13 | gem install rspec-kickstarter 14 | 15 | ## Usage 16 | 17 | rspec-kickstarter ./app 18 | rspec-kickstarter ./lib 19 | rspec-kickstarter ./lib/yourapp/util.rb 20 | 21 | ## Options 22 | 23 | ``` 24 | $ rspec-kickstarter -h 25 | Usage: rspec-kickstarter [options] 26 | -f Create if absent or append to the existing spec 27 | --force 28 | -n Dry run mode (shows generated code to console) 29 | --dry-run 30 | -r Run in Rails mode 31 | --rails 32 | -o VAL Output directory (default: ./spec) 33 | --output-dir VAL 34 | -D VAL Delta tempalte path (e.g. ./rails_controller_delta.erb) 35 | --delta-template VAL 36 | -F VAL Full template path (e.g. ./rails_controller_full.erb) 37 | --full-template VAL 38 | -v Print version 39 | --version 40 | ``` 41 | 42 | ## Output example 43 | 44 | Unfortunately, `lib/foo/bar_baz.rb` has no test. That's too bad... 45 | 46 | ```ruby 47 | module Foo 48 | class BarBaz 49 | 50 | def self.xxx(a, b = "aaa") 51 | end 52 | 53 | def yyy() 54 | end 55 | 56 | private 57 | 58 | def zzz(a) 59 | end 60 | 61 | end 62 | end 63 | ``` 64 | 65 | OK, run `rspec-kickstarter` now! 66 | 67 | ```sh 68 | $ rspec-kickstarter lib/foo/bar_baz.rb 69 | ./spec/foo/bar_baz_spec.rb created. 70 | ``` 71 | 72 | `spec/foo/bar_baz_spec.rb` will be created as follows. 73 | 74 | ```ruby 75 | # -*- encoding: utf-8 -*- 76 | require 'spec_helper' 77 | require 'foo/bar_baz' 78 | 79 | describe Foo::BarBaz do 80 | 81 | # TODO: auto-generated 82 | describe '#xxx' do 83 | it 'works' do 84 | a = double('a') 85 | b = double('b') 86 | result = Foo::BarBaz.xxx(a, b) 87 | expect(result).not_to be_nil 88 | end 89 | end 90 | 91 | # TODO: auto-generated 92 | describe '#yyy' do 93 | it 'works' do 94 | bar_baz = Foo::BarBaz.new 95 | result = bar_baz.yyy() 96 | expect(result).not_to be_nil 97 | end 98 | end 99 | 100 | end 101 | ``` 102 | 103 | ## Appending lacking test templates 104 | 105 | `-f` option allows appending lacking test templates to existing specs. 106 | 107 | For instance, `additional_ops` method is added after spec creation. 108 | 109 | ```ruby 110 | module Foo 111 | class BarBaz 112 | 113 | def self.xxx(a, b = "aaa") 114 | end 115 | 116 | def yyy() 117 | end 118 | 119 | def additional_ops 120 | end 121 | 122 | private 123 | 124 | def zzz(a) 125 | end 126 | 127 | end 128 | end 129 | ``` 130 | 131 | Execute command. 132 | 133 | `rspec-kickstarter -f lib/foo/bar_baz.rb` 134 | 135 | The following code will be appended. 136 | 137 | ```ruby 138 | 139 | # TODO: auto-generated 140 | describe '#additional_ops' do 141 | it 'works' do 142 | bar_baz = Foo::BarBaz.new 143 | result = bar_baz.additional_ops() 144 | expect(result).not_to be_nil 145 | end 146 | end 147 | 148 | end 149 | ``` 150 | 151 | ## Rails mode 152 | 153 | In Rails mode, rspec-kickstarter generates Rails way spec code for controllers and helpers. 154 | 155 | ``` 156 | $ rspec-kickstarter -r app/controllers/root_controller.rb 157 | ``` 158 | 159 | Output for scaffold: 160 | 161 | ```ruby 162 | # -*- encoding: utf-8 -*- 163 | 164 | require 'rails_helper' 165 | 166 | describe CommentsController do 167 | 168 | # TODO: auto-generated 169 | describe 'GET index' do 170 | it 'works' do 171 | get :index, {}, {} 172 | expect(response.status).to eq(200) 173 | end 174 | end 175 | 176 | # TODO: auto-generated 177 | describe 'GET show' do 178 | it 'works' do 179 | get :show, {}, {} 180 | expect(response.status).to eq(200) 181 | end 182 | end 183 | 184 | # TODO: auto-generated 185 | describe 'GET new' do 186 | it 'works' do 187 | get :new, {}, {} 188 | expect(response.status).to eq(200) 189 | end 190 | end 191 | 192 | # TODO: auto-generated 193 | describe 'GET edit' do 194 | it 'works' do 195 | get :edit, {}, {} 196 | expect(response.status).to eq(200) 197 | end 198 | end 199 | 200 | # TODO: auto-generated 201 | describe 'POST create' do 202 | it 'works' do 203 | post :create, {}, {} 204 | expect(response.status).to eq(200) 205 | end 206 | end 207 | 208 | # TODO: auto-generated 209 | describe 'PUT update' do 210 | it 'works' do 211 | put :update, {}, {} 212 | expect(response.status).to eq(200) 213 | end 214 | end 215 | 216 | # TODO: auto-generated 217 | describe 'DELETE destroy' do 218 | it 'works' do 219 | delete :destroy, {}, {} 220 | expect(response.status).to eq(200) 221 | end 222 | end 223 | 224 | end 225 | ``` 226 | 227 | 228 | ## Customizable code template 229 | 230 | Try the template_samples. 231 | 232 | ``` 233 | ruby -Ilib bin/rspec-kickstarter --delta-template=samples/delta_template.erb --full-template=samples/full_template.erb lib/foo.rb -n 234 | ``` 235 | 236 | When you use customized templates for your apps, `gem install rspec-kickstarter` and do like this: 237 | 238 | ``` 239 | rspec-kickstarter lib -D misc/delta_template.erb -F misc/full_template.erb 240 | ``` 241 | 242 | ## RubyKaigi 2013 243 | 244 | Lightning talk about rspec-kickstarter at RubyKaigi 2013 245 | 246 | http://rubykaigi.org/2013/lightning_talks#seratch 247 | 248 | https://speakerdeck.com/seratch/a-test-code-generator-for-rspec-users 249 | 250 | ## Related Projects 251 | 252 | ### Vintage fork 253 | 254 | https://github.com/ifad/rspec-kickstarter-vintage 255 | 256 | This fork supports ruby 1.8.7 and RSpec 1.x with the old syntax. 257 | 258 | ### ToFactory 259 | 260 | https://github.com/markburns/to_factory 261 | 262 | ToFactory is a FactoryGirl's factories code generator for existing projects. 263 | 264 | ## License 265 | 266 | Copyright (c) 2013 - Kazuhiro Sera 267 | 268 | MIT License 269 | 270 | https://github.com/seratch/rspec-kickstarter/blob/master/LICENSE.txt 271 | 272 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /bin/rspec-kickstarter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # rspec-kickstarter [dir/*.rb] 4 | # 5 | 6 | require 'optparse' 7 | require 'rspec_kickstarter/version' 8 | require 'rspec_kickstarter/generator' 9 | print_version = false 10 | force_write = false 11 | dry_run = false 12 | rails_mode = false 13 | spec_dir = './spec' 14 | delta_path = nil 15 | full_path = nil 16 | 17 | opt = OptionParser.new 18 | opt.on('-f', 'Create if absent or append to the existing spec') { |_| force_write = true } 19 | opt.on('--force', '') { |_| force_write = true } 20 | opt.on('-n', 'Dry run mode (shows generated code to console)') { |_| dry_run = true } 21 | opt.on('--dry-run', '') { |_| dry_run = true } 22 | opt.on('-r', 'Run in Rails mode') { |_| rails_mode = true } 23 | opt.on('--rails', '') { |_| rails_mode = true } 24 | opt.on('-o VAL', 'Output directory (default: ./spec)') { |dir| spec_dir = dir } 25 | opt.on('--output-dir VAL', '') { |dir| spec_dir = dir } 26 | opt.on('-D VAL', 'Delta tempalte path (e.g. ./rails_controller_delta.erb)') { |path| delta_path = path } 27 | opt.on('--delta-template VAL', '') { |path| delta_path = path } 28 | opt.on('-F VAL', 'Full template path (e.g. ./rails_controller_full.erb)') { |path| full_path = path } 29 | opt.on('--full-template VAL', '') { |path| full_path = path } 30 | opt.on('-v', 'Print version') { |_| print_version = true } 31 | opt.on('--version', '') { |_| print_version = true } 32 | 33 | args = opt.parse(ARGV) 34 | 35 | if print_version 36 | puts "rspec-kickstarter #{RSpecKickstarter::VERSION}" 37 | exit 0 38 | end 39 | 40 | dir_or_file = args.first 41 | if dir_or_file.nil? 42 | puts "Usage: rspec-kickstarter [dir/*.rb] -options" 43 | exit 1 44 | end 45 | unless dir_or_file.match(/.rb$/) 46 | dir_or_file = dir_or_file.gsub(/\/$/, '') + "/**/*.rb" 47 | end 48 | 49 | delta_template = nil 50 | if ! delta_path.nil? 51 | if File.exist?(delta_path) 52 | delta_template = File.read(delta_path) 53 | else 54 | puts "'#{delta_path}' is not found." 55 | exit 1 56 | end 57 | end 58 | full_template = nil 59 | if ! full_path.nil? 60 | if File.exist?(full_path) 61 | full_template = File.read(full_path) 62 | else 63 | puts "'#{full_path}' is not found." 64 | exit 1 65 | end 66 | end 67 | 68 | generator = RSpecKickstarter::Generator.new(spec_dir, delta_template, full_template) 69 | 70 | Dir.glob(dir_or_file).each do |file_path| 71 | generator.write_spec(file_path, force_write, dry_run, rails_mode) 72 | end 73 | 74 | -------------------------------------------------------------------------------- /lib/rspec_kickstarter.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'rspec_kickstarter/generator' 4 | require 'rspec_kickstarter/version' 5 | 6 | # 7 | # RSpecKickstarter Facade 8 | # 9 | module RSpecKickstarter 10 | 11 | def self.write_spec(file_path, spec_dir = './spec', force_write = false, dry_run = false) 12 | generator = RSpecKickstarter::Generator.new(spec_dir) 13 | generator.write_spec(file_path, force_write, dry_run) 14 | end 15 | 16 | end 17 | 18 | -------------------------------------------------------------------------------- /lib/rspec_kickstarter/erb_factory.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'erb' 4 | require 'rspec_kickstarter' 5 | require 'rspec_kickstarter/erb_templates' 6 | 7 | # 8 | # ERB instance provider 9 | # 10 | module RSpecKickstarter 11 | class ERBFactory 12 | 13 | def initialize(custom_template) 14 | @custom_template = custom_template 15 | end 16 | 17 | # 18 | # Returns ERB instance for creating new spec 19 | # 20 | def get_instance_for_new_spec(rails_mode, target_path) 21 | template = get_erb_template(@custom_template, true, rails_mode, target_path) 22 | ERB.new(template, nil, '-', '_new_spec_code') 23 | end 24 | 25 | # 26 | # Returns ERB instance for appeding lacking tests 27 | # 28 | def get_instance_for_appending(rails_mode, target_path) 29 | template = get_erb_template(@custom_template, false, rails_mode, target_path) 30 | ERB.new(template, nil, '-', '_additional_spec_code') 31 | end 32 | 33 | private 34 | 35 | # 36 | # Returns ERB template 37 | # 38 | def get_erb_template(custom_template, is_full, rails_mode, target_path) 39 | if custom_template 40 | custom_template 41 | elsif rails_mode && target_path.match(/controllers/) 42 | get_rails_controller_template(is_full) 43 | elsif rails_mode && target_path.match(/helpers/) 44 | get_rails_helper_template(is_full) 45 | else 46 | get_basic_template(is_full) 47 | end 48 | end 49 | 50 | def get_rails_controller_template(is_full) 51 | if is_full 52 | RSpecKickstarter::ERBTemplates::RAILS_CONTROLLER_NEW_SPEC_TEMPLATE 53 | else 54 | RSpecKickstarter::ERBTemplates::RAILS_CONTROLLER_METHODS_PART_TEMPLATE 55 | end 56 | end 57 | 58 | def get_rails_helper_template(is_full) 59 | if is_full 60 | RSpecKickstarter::ERBTemplates::RAILS_HELPER_NEW_SPEC_TEMPLATE 61 | else 62 | RSpecKickstarter::ERBTemplates::RAILS_HELPER_METHODS_PART_TEMPLATE 63 | end 64 | end 65 | 66 | def get_basic_template(is_full) 67 | if is_full 68 | RSpecKickstarter::ERBTemplates::BASIC_NEW_SPEC_TEMPLATE 69 | else 70 | RSpecKickstarter::ERBTemplates::BASIC_METHODS_PART_TEMPLATE 71 | end 72 | end 73 | 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/rspec_kickstarter/erb_templates.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'erb' 4 | require 'rspec_kickstarter' 5 | 6 | # 7 | # ERB templates 8 | # 9 | module RSpecKickstarter 10 | module ERBTemplates 11 | 12 | BASIC_METHODS_PART_TEMPLATE = < 14 | # TODO: auto-generated 15 | describe '#<%= method.name %>' do 16 | it 'works' do 17 | <%- unless get_instantiation_code(c, method).nil? -%><%= get_instantiation_code(c, method) %><%- end -%> 18 | <%- unless get_params_initialization_code(method).nil? -%><%= get_params_initialization_code(method) %><%- end -%> 19 | result = <%= get_method_invocation_code(c, method) %> 20 | expect(result).not_to be_nil 21 | end 22 | end 23 | <% } %> 24 | SPEC 25 | 26 | BASIC_NEW_SPEC_TEMPLATE = <require '<%= self_path %>' 31 | <% end -%> 32 | 33 | describe <%= get_complete_class_name(c) %> do 34 | <%= ERB.new(BASIC_METHODS_PART_TEMPLATE, nil, '-').result(binding) -%> 35 | end 36 | SPEC 37 | 38 | RAILS_CONTROLLER_METHODS_PART_TEMPLATE = < 40 | # TODO: auto-generated 41 | describe '<%= get_rails_http_method(method.name).upcase %> <%= method.name %>' do 42 | it 'works' do 43 | <%= get_rails_http_method(method.name) %> :<%= method.name %>, {}, {} 44 | expect(response.status).to eq(200) 45 | end 46 | end 47 | <% } %> 48 | SPEC 49 | 50 | RAILS_CONTROLLER_NEW_SPEC_TEMPLATE = < do 56 | <%= ERB.new(RAILS_CONTROLLER_METHODS_PART_TEMPLATE, nil, '-').result(binding) -%> 57 | end 58 | SPEC 59 | 60 | RAILS_HELPER_METHODS_PART_TEMPLATE = < 62 | # TODO: auto-generated 63 | describe '#<%= method.name %>' do 64 | it 'works' do 65 | result = <%= get_rails_helper_method_invocation_code(method) %> 66 | expect(result).not_to be_nil 67 | end 68 | end 69 | <% } %> 70 | SPEC 71 | 72 | RAILS_HELPER_NEW_SPEC_TEMPLATE = < do 78 | <%= ERB.new(RAILS_HELPER_METHODS_PART_TEMPLATE, nil, '-').result(binding) -%> 79 | end 80 | SPEC 81 | 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /lib/rspec_kickstarter/generator.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'rdoc' 4 | require 'rspec_kickstarter' 5 | require 'rspec_kickstarter/erb_factory' 6 | require 'rspec_kickstarter/erb_templates' 7 | require 'rspec_kickstarter/rdoc_factory' 8 | 9 | # 10 | # RSpec Code Generator 11 | # 12 | module RSpecKickstarter 13 | class Generator 14 | include RSpecKickstarter::ERBTemplates 15 | 16 | attr_accessor :spec_dir, :delta_template, :full_template 17 | 18 | def initialize(spec_dir = './spec', delta_template = nil, full_template = nil) 19 | @spec_dir = spec_dir.gsub(/\/$/, '') 20 | @delta_template = delta_template 21 | @full_template = full_template 22 | end 23 | 24 | # 25 | # Writes new spec or appends to the existing spec. 26 | # 27 | def write_spec(file_path, force_write = false, dry_run = false, rails_mode = false) 28 | class_or_module = RSpecKickstarter::RDocFactory.get_rdoc_class_or_module(file_path) 29 | if class_or_module 30 | spec_path = get_spec_path(file_path) 31 | if force_write && File.exist?(spec_path) 32 | append_to_existing_spec(class_or_module, dry_run, rails_mode, spec_path) 33 | else 34 | create_new_spec(class_or_module, dry_run, rails_mode, file_path, spec_path) 35 | end 36 | else 37 | puts "#{file_path} skipped (Class/Module not found)." 38 | end 39 | end 40 | 41 | # 42 | # Gets the complete class name from RDoc::NormalClass/RDoc::NormalModule instance. 43 | # 44 | def get_complete_class_name(class_or_module, name = class_or_module.name) 45 | if !class_or_module.parent.name.nil? && class_or_module.parent.is_a?(RDoc::NormalModule) 46 | get_complete_class_name(class_or_module.parent, "#{class_or_module.parent.name}::#{name}") 47 | else 48 | name 49 | end 50 | end 51 | 52 | # 53 | # Returns spec file path. 54 | # e.g. "lib/foo/bar_baz.rb" -> "spec/foo/bar_baz_spec.rb" 55 | # 56 | def get_spec_path(file_path) 57 | spec_dir + '/' + file_path.gsub(/^\.\//, '').gsub(%r{^(lib/)|(app/)}, '').gsub(/\.rb$/, '_spec.rb') 58 | end 59 | 60 | # 61 | # Returns string value to require. 62 | # e.g. "lib/foo/bar_baz.rb" -> "foo/bar_baz" 63 | # 64 | def to_string_value_to_require(file_path) 65 | file_path.gsub(%r{^(lib/)|(app/)}, '').gsub(/\.rb$/, '') 66 | end 67 | 68 | # 69 | # Returns snake_case name. 70 | # e.g. FooBar -> "foo_bar" 71 | # 72 | def instance_name(c) 73 | c.name. 74 | gsub(/::/, '/'). 75 | gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2'). 76 | gsub(/([a-z\d])([A-Z])/, '\1_\2'). 77 | tr('-', '_'). 78 | downcase 79 | end 80 | 81 | # 82 | # Extracts parameter names as an *Array*. 83 | # e.g. "()" -> [] 84 | # e.g. "(a, b = 'foo')" -> ["a", "b"] 85 | # 86 | def to_param_names_array(params) 87 | params.split(',').map { |p| p.gsub(/[\(\)\s]/, '').gsub(/=.+$/, '') }.reject { |p| p.nil? || p.empty? } 88 | end 89 | 90 | # 91 | # Returns params part 92 | # e.g. ["a","b"] -> "(a, b)" 93 | # e.g. [] -> "" 94 | # 95 | def to_params_part(params) 96 | param_csv = to_param_names_array(params).join(', ') 97 | param_csv.empty? ? '' : "(#{param_csv})" 98 | end 99 | 100 | # 101 | # Creates new spec. 102 | # 103 | # rubocop:disable Metrics/AbcSize 104 | def create_new_spec(class_or_module, dry_run, rails_mode, file_path, spec_path) 105 | # These names are used in ERB template, don't delete. 106 | # rubocop:disable Lint/UselessAssignment 107 | methods_to_generate = class_or_module.method_list.select { |m| m.visibility == :public } 108 | c = class_or_module 109 | self_path = to_string_value_to_require(file_path) 110 | # rubocop:enable Lint/UselessAssignment 111 | 112 | erb = RSpecKickstarter::ERBFactory.new(@full_template).get_instance_for_new_spec(rails_mode, file_path) 113 | code = erb.result(binding) 114 | 115 | if dry_run 116 | puts "----- #{spec_path} -----" 117 | puts code 118 | else 119 | if File.exist?(spec_path) 120 | puts "#{spec_path} already exists." 121 | else 122 | FileUtils.mkdir_p(File.dirname(spec_path)) 123 | File.open(spec_path, 'w') { |f| f.write(code) } 124 | puts "#{spec_path} created." 125 | end 126 | end 127 | end 128 | 129 | # rubocop:enable Metrics/AbcSize 130 | 131 | # 132 | # Appends new tests to the existing spec. 133 | # 134 | # rubocop:disable Metrics/AbcSize 135 | def append_to_existing_spec(class_or_module, dry_run, rails_mode, spec_path) 136 | existing_spec = File.read(spec_path) 137 | lacking_methods = class_or_module.method_list. 138 | select { |m| m.visibility == :public }. 139 | reject { |m| existing_spec.match(m.name) } 140 | 141 | if lacking_methods.empty? 142 | puts "#{spec_path} skipped." 143 | else 144 | # These names are used in ERB template, don't delete. 145 | # rubocop:disable Lint/UselessAssignment 146 | methods_to_generate = lacking_methods 147 | c = class_or_module 148 | # rubocop:enable Lint/UselessAssignment 149 | 150 | erb = RSpecKickstarter::ERBFactory.new(@delta_template).get_instance_for_appending(rails_mode, spec_path) 151 | additional_spec = erb.result(binding) 152 | 153 | last_end_not_found = true 154 | code = existing_spec.split("\n").reverse.reject { |line| 155 | before_modified = last_end_not_found 156 | last_end_not_found = line.gsub(/#.+$/, '').strip != 'end' if before_modified 157 | before_modified 158 | }.reverse.join("\n") + "\n" + additional_spec + "\nend\n" 159 | 160 | if dry_run 161 | puts "----- #{spec_path} -----" 162 | puts code 163 | else 164 | File.open(spec_path, 'w') { |f| f.write(code) } 165 | end 166 | puts "#{spec_path} modified." 167 | end 168 | end 169 | 170 | # rubocop:enable Metrics/AbcSize 171 | 172 | # ----- 173 | # Code generation 174 | # ----- 175 | 176 | # 177 | # e.g. 178 | # a = double('a') 179 | # b = double('b') 180 | # bar_baz = BarBaz.new(a, b) 181 | # 182 | def get_instantiation_code(c, method) 183 | if method.singleton 184 | '' 185 | else 186 | constructor = c.method_list.find { |m| m.name == 'new' } 187 | if constructor.nil? 188 | " #{instance_name(c)} = #{get_complete_class_name(c)}.new\n" 189 | else 190 | get_params_initialization_code(constructor) + 191 | " #{instance_name(c)} = #{get_complete_class_name(c)}.new#{to_params_part(constructor.params)}\n" 192 | end 193 | end 194 | end 195 | 196 | # 197 | # e.g. 198 | # a = double('a') 199 | # b = double('b') 200 | # 201 | def get_params_initialization_code(method) 202 | code = to_param_names_array(method.params).map { |p| " #{p} = double('#{p}')" }.join("\n") 203 | code.empty? ? '' : "#{code}\n" 204 | end 205 | 206 | # 207 | # e.g. BarBaz.do_something(a, b) { |c| } 208 | # 209 | def get_method_invocation_code(c, method) 210 | target = method.singleton ? get_complete_class_name(c) : instance_name(c) 211 | "#{target}.#{method.name}#{to_params_part(method.params)}#{get_block_code(method)}" 212 | end 213 | 214 | # 215 | # e.g. do_something(a, b) { |c| } 216 | # 217 | def get_rails_helper_method_invocation_code(method) 218 | "#{method.name}#{to_params_part(method.params)}#{get_block_code(method)}" 219 | end 220 | 221 | # 222 | # e.g. { |a, b| } 223 | # 224 | def get_block_code(method) 225 | if method.block_params.nil? || method.block_params.empty? 226 | '' 227 | else 228 | " { |#{method.block_params}| }" 229 | end 230 | end 231 | 232 | def get_rails_http_method(method_name) 233 | http_method = RAILS_RESOURCE_METHOD_AND_HTTP_METHOD[method_name] 234 | http_method.nil? ? 'get' : http_method 235 | end 236 | 237 | RAILS_RESOURCE_METHOD_AND_HTTP_METHOD = { 238 | 'index' => 'get', 239 | 'new' => 'get', 240 | 'create' => 'post', 241 | 'show' => 'get', 242 | 'edit' => 'get', 243 | 'update' => 'put', 244 | 'destroy' => 'delete' 245 | } 246 | 247 | end 248 | end 249 | 250 | -------------------------------------------------------------------------------- /lib/rspec_kickstarter/rdoc_factory.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'rdoc' 4 | require 'rdoc/generator' 5 | require 'rdoc/options' 6 | require 'rdoc/parser/ruby' 7 | require 'rdoc/stats' 8 | require 'rspec_kickstarter' 9 | 10 | # 11 | # RDoc instance factory 12 | # 13 | module RSpecKickstarter 14 | class RDocFactory 15 | 16 | # 17 | # Returns RDoc::NormalClass/RDoc::NormalModule instance. 18 | # 19 | def self.get_rdoc_class_or_module(file_path) 20 | top_level = get_ruby_parser(file_path).scan 21 | extract_target_class_or_module(top_level) 22 | end 23 | 24 | # 25 | # Creates new RDoc::Parser::Ruby instance. 26 | # 27 | def self.get_ruby_parser(file_path) 28 | top_level = RDoc::TopLevel.new(file_path) 29 | if RUBY_VERSION.to_f < 2.0 30 | # reset is removed since 2.0 31 | RDoc::TopLevel.reset 32 | end 33 | 34 | # RDoc::Stats initialization 35 | if defined?(RDoc::Store) 36 | # RDoc 4.0.0 requires RDoc::Store internally. 37 | store = RDoc::Store.new 38 | top_level.store = store 39 | stats = RDoc::Stats.new(store, 1) 40 | else 41 | stats = RDoc::Stats.new(1) 42 | end 43 | 44 | RDoc::Parser::Ruby.new( 45 | top_level, 46 | file_path, 47 | File.read(file_path), 48 | RDoc::Options.new, 49 | stats 50 | ) 51 | end 52 | 53 | # 54 | # Extracts RDoc::NormalClass/RDoc::NormalModule from RDoc::TopLevel. 55 | # 56 | def self.extract_target_class_or_module(top_level) 57 | c = top_level.classes.first 58 | if c.nil? 59 | m = top_level.modules.first 60 | if m.nil? 61 | top_level.is_a?(RDoc::NormalModule) ? top_level : nil 62 | else 63 | extract_target_class_or_module(m) 64 | end 65 | else 66 | c 67 | end 68 | end 69 | 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/rspec_kickstarter/version.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Gem version 5 | # 6 | module RSpecKickstarter 7 | VERSION = '1.0.2' 8 | end 9 | -------------------------------------------------------------------------------- /rspec-kickstarter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | current_dir=`dirname $0` 4 | cd ${current_dir} 5 | 6 | ruby -I ./lib ./bin/rspec-kickstarter $@ 7 | 8 | -------------------------------------------------------------------------------- /rspec-kickstarter.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'rspec_kickstarter/version' 5 | 6 | Gem::Specification.new do |gem| 7 | gem.name = "rspec-kickstarter" 8 | gem.version = RSpecKickstarter::VERSION 9 | gem.authors = ["Kazuhiro Sera"] 10 | gem.email = ["seratch@gmail.com"] 11 | gem.licenses = ["MIT"] 12 | gem.description = %q{rspec-kickstarter supports you writing tests for existing code.} 13 | gem.summary = %q{rspec-kickstarter supports you writing tests for existing code.} 14 | gem.homepage = "https://github.com/seratch/rspec-kickstarter" 15 | gem.files = Dir["{bin,lib}/**/*"] 16 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 17 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 18 | gem.require_paths = ["lib"] 19 | end 20 | -------------------------------------------------------------------------------- /samples/delta_template.erb: -------------------------------------------------------------------------------- 1 | <%- methods_to_generate.map { |method| %> 2 | # TODO auto-generated 3 | describe '#<%= method.name %>' do 4 | it 'works' do 5 | result = <%= get_rails_helper_method_invocation_code(method) %> 6 | expect(result).not_to be_nil 7 | end 8 | end 9 | <% } %> 10 | -------------------------------------------------------------------------------- /samples/full_template.erb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'spec_helper' 4 | 5 | describe <%= get_complete_class_name(c) %> do 6 | <%= ERB.new(@delta_template, nil, '-').result(binding) -%> 7 | end 8 | 9 | -------------------------------------------------------------------------------- /spec/rspec_kickstarter/generator_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'rspec_kickstarter/generator' 4 | 5 | describe RSpecKickstarter::Generator do 6 | 7 | let(:generator) { RSpecKickstarter::Generator.new('tmp/spec') } 8 | 9 | describe '#new' do 10 | it 'works without params' do 11 | result = RSpecKickstarter::Generator.new 12 | expect(result).not_to be_nil 13 | end 14 | it 'works' do 15 | spec_dir = './spec' 16 | 17 | result = RSpecKickstarter::Generator.new(spec_dir) 18 | expect(result).not_to be_nil 19 | end 20 | end 21 | 22 | describe '#get_complete_class_name' do 23 | it 'works' do 24 | parent = double(:parent, name: nil) 25 | c = double(:c, parent: parent) 26 | name = 'ClassName' 27 | 28 | result = generator.get_complete_class_name(c, name) 29 | expect(result).to eq('ClassName') 30 | end 31 | end 32 | 33 | describe '#instance_name' do 34 | it 'works' do 35 | c = double(:c, name: 'generator') 36 | 37 | result = generator.instance_name(c) 38 | expect(result).to eq('generator') 39 | end 40 | end 41 | 42 | describe '#to_param_names_array' do 43 | it 'works' do 44 | params = "(a, b = 'foo', c = 123)" 45 | 46 | result = generator.to_param_names_array(params) 47 | expect(result).to eq(%w(a b c)) 48 | end 49 | end 50 | 51 | describe '#get_params_initialization_code' do 52 | it 'works' do 53 | method = double(:method, params: "(a = 1,b = 'aaaa')") 54 | 55 | result = generator.get_params_initialization_code(method) 56 | expect(result).to eq(" a = double('a')\n b = double('b')\n") 57 | end 58 | end 59 | 60 | describe '#get_instantiation_code' do 61 | it 'works with modules' do 62 | method = double(:method, singleton: true, name: 'do_something') 63 | c = double(:c, name: 'Foo', method_list: [method]) 64 | 65 | result = generator.get_instantiation_code(c, method) 66 | expect(result).to eq('') 67 | end 68 | 69 | it 'works with classes' do 70 | parent = double(:parent, name: nil) 71 | method = double(:method, singleton: false, name: 'do_something') 72 | c = double(:c, name: 'Foo', parent: parent, method_list: [method]) 73 | 74 | result = generator.get_instantiation_code(c, method) 75 | expect(result).to eq(" foo = Foo.new\n") 76 | end 77 | end 78 | 79 | describe '#get_method_invocation_code' do 80 | it 'works with modules' do 81 | parent = double(:parent, name: nil) 82 | method = double(:method, singleton: true, name: 'do_something', params: '(a, b)', block_params: '') 83 | c = double(:c, name: 'Module', parent: parent, method_list: [method]) 84 | 85 | result = generator.get_method_invocation_code(c, method) 86 | expect(result).to eq('Module.do_something(a, b)') 87 | end 88 | it 'works with classes' do 89 | parent = double(:parent, name: 'Module') 90 | method = double(:method, singleton: false, name: 'do_something', params: '(a, b)', block_params: '') 91 | c = double(:c, name: 'ClassName', parent: parent, method_list: [method]) 92 | 93 | result = generator.get_method_invocation_code(c, method) 94 | expect(result).to eq('class_name.do_something(a, b)') 95 | end 96 | end 97 | 98 | describe '#get_block_code' do 99 | it 'works with no arg' do 100 | method = double(:method, block_params: '') 101 | 102 | result = generator.get_block_code(method) 103 | expect(result).to eq('') 104 | end 105 | it 'works with 1 arg block' do 106 | method = double(:method, block_params: 'a') 107 | 108 | result = generator.get_block_code(method) 109 | expect(result).to eq(' { |a| }') 110 | end 111 | it 'works with 2 args block' do 112 | method = double(:method, block_params: 'a, b') 113 | 114 | result = generator.get_block_code(method) 115 | expect(result).to eq(' { |a, b| }') 116 | end 117 | end 118 | 119 | class CannotExtractTargetClass < RSpecKickstarter::Generator 120 | def extract_target_class_or_module(*) 121 | nil 122 | end 123 | end 124 | 125 | describe '#write_spec' do 126 | 127 | it 'just works' do 128 | file_path = 'lib/rspec_kickstarter.rb' 129 | generator.write_spec(file_path) 130 | end 131 | 132 | it 'works with -f option' do 133 | file_path = 'lib/rspec_kickstarter.rb' 134 | generator.write_spec(file_path, true) 135 | end 136 | 137 | it 'works with -n option' do 138 | file_path = 'lib/rspec_kickstarter.rb' 139 | generator.write_spec(file_path, false, true) 140 | end 141 | 142 | it 'works with no target class' do 143 | file_path = 'lib/rspec_kickstarter.rb' 144 | CannotExtractTargetClass.new.write_spec(file_path, true) 145 | end 146 | 147 | it 'creates new spec with full_tempalte' do 148 | FileUtils.rm_rf('tmp/spec') if File.exist?('tmp/spec') 149 | FileUtils.mkdir_p('tmp/spec') 150 | 151 | code = <