rspec_for_generators 0.2.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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.markdown +111 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/lib/generators/demo/demo_generator.rb +91 -0
- data/lib/rspec_for_generators.rb +11 -0
- data/lib/rspec_for_generators/fixtures/routes.rb +2 -0
- data/lib/rspec_for_generators/generator_spec_helper.rb +73 -0
- data/lib/rspec_for_generators/main.rb +7 -0
- data/lib/rspec_for_generators/matchers/content/all.rb +1 -0
- data/lib/rspec_for_generators/matchers/content/have_class.rb +36 -0
- data/lib/rspec_for_generators/matchers/content/have_method.rb +49 -0
- data/lib/rspec_for_generators/matchers/content/have_module.rb +34 -0
- data/lib/rspec_for_generators/matchers/content/include_module.rb +36 -0
- data/lib/rspec_for_generators/matchers/content/inherit_from.rb +33 -0
- data/lib/rspec_for_generators/matchers/file/all.rb +1 -0
- data/lib/rspec_for_generators/matchers/file/generate_file.rb +73 -0
- data/lib/rspec_for_generators/matchers/file/generate_migration.rb +43 -0
- data/lib/rspec_for_generators/matchers/helpers/content.rb +20 -0
- data/lib/rspec_for_generators/matchers/helpers/file.rb +28 -0
- data/lib/rspec_for_generators/rails_helpers/all.rb +6 -0
- data/lib/rspec_for_generators/rails_helpers/rails_app.rb +55 -0
- data/lib/rspec_for_generators/rails_helpers/rails_controller.rb +34 -0
- data/lib/rspec_for_generators/rails_helpers/rails_helper.rb +36 -0
- data/lib/rspec_for_generators/rails_helpers/rails_mailer.rb +29 -0
- data/lib/rspec_for_generators/rails_helpers/rails_model.rb +94 -0
- data/lib/rspec_for_generators/rails_helpers/rails_view.rb +29 -0
- data/lib/rspec_for_generators/rails_spec_helper.rb +17 -0
- data/lib/rspec_for_generators/rspec_test_case.rb +26 -0
- data/rspec_for_generators.gemspec +96 -0
- data/spec/rspec_for_generators/rspec_for_generators_spec.rb +43 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/tmp/rails/config/routes.rb +2 -0
- data/wiki/Custom Rails 3 Generators.textile +110 -0
- metadata +195 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Kristian Mandrup
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# RSpec 2 library for specifying and testing generators
|
2
|
+
|
3
|
+
RSpec 2 matchers, helpers and various utilities to assist in writing generator specs especially Rails 3 generators.
|
4
|
+
|
5
|
+
This project was extracted from my experiments with creating generators for jnunemaker's *Canable*, see [My fork of Canable](http://github.com/kristianmandrup/canable).
|
6
|
+
|
7
|
+
I attempted to test the generators I built but I noticed, that the only option I could find, was to use a special Rails TestCase class created for Test-Unit.
|
8
|
+
So I thought I could wrap it to be used with RSpec 2; my BDD testing framework of choice!
|
9
|
+
|
10
|
+
## Install
|
11
|
+
|
12
|
+
<code>gem install rspec_for_generators</code>
|
13
|
+
|
14
|
+
To install using edge
|
15
|
+
|
16
|
+
<code>rake install</code>
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
The following demonstrates an example usage. There are many more options and cool DSL convenience methods. Check out the code!
|
21
|
+
|
22
|
+
<pre>
|
23
|
+
# spec/spec_helper.rb
|
24
|
+
require 'rspec'
|
25
|
+
|
26
|
+
# This is required for rails_spec_helper.rb to work. Not sure how to better set this configuration value.
|
27
|
+
# It's the relative root for which the Rails mock app is created. So if it's set to point to the spec folder,
|
28
|
+
# then rails will be put under ../tmp, relative to /spec, so that /tmp will be a folder in the current project root.
|
29
|
+
# Note: In the near future I will provide a better way to achieve this by hooking into some step in the Rails 3 loading behavior
|
30
|
+
|
31
|
+
module Rails
|
32
|
+
def config_root_dir
|
33
|
+
File.dirname(__FILE)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# load this rspec toolbox to help spec generators
|
38
|
+
require 'rspec_for_generators'
|
39
|
+
|
40
|
+
<pre>
|
41
|
+
|
42
|
+
<pre>
|
43
|
+
# spec/generators/canable.rb
|
44
|
+
require_generators :canable => ['model', 'user']
|
45
|
+
</pre>
|
46
|
+
|
47
|
+
<pre>
|
48
|
+
# spec/generators/model_generator_spec.rb
|
49
|
+
|
50
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
51
|
+
|
52
|
+
# list of generators to spec are loaded
|
53
|
+
require 'generators/canable'
|
54
|
+
|
55
|
+
describe 'model_generator' do
|
56
|
+
# include Rails model helpers for AciveRecord
|
57
|
+
# also available are: MongoMapper, Mongoid and DataMapper
|
58
|
+
# mongo_mapper, :data_mapper, :mongoid
|
59
|
+
|
60
|
+
model_helper_for :active_record
|
61
|
+
|
62
|
+
before :each do
|
63
|
+
# define generator to test
|
64
|
+
RSpec::Generator.setup_generator 'model_generator' do
|
65
|
+
tests Canable::Generators::ModelGenerator
|
66
|
+
end
|
67
|
+
# ensure clean state before run
|
68
|
+
remove_model 'account'
|
69
|
+
end
|
70
|
+
|
71
|
+
after :each do
|
72
|
+
# ensure clean state after run
|
73
|
+
remove_model 'account'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not work without an existing Account model file" do
|
77
|
+
RSpec::Generator.with_generator do |g|
|
78
|
+
name = 'account'
|
79
|
+
g.run_generator %w{account}
|
80
|
+
g.should_not generate_file name, :model
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should decorate an existing Account model file with 'include Canable:Ables'" do
|
85
|
+
RSpec::Generator.with_generator do |g|
|
86
|
+
name = 'account'
|
87
|
+
create_model name
|
88
|
+
g.run_generator %w{account}
|
89
|
+
g.should generate_file name, :model do |content|
|
90
|
+
content.should have_class name.camelize do |klass|
|
91
|
+
klass.should include_module 'Canable::Ables'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
</pre>
|
98
|
+
|
99
|
+
## Note on Patches/Pull Requests
|
100
|
+
|
101
|
+
* Fork the project.
|
102
|
+
* Make your feature addition or bug fix.
|
103
|
+
* Add tests for it. This is important so I don't break it in a
|
104
|
+
future version unintentionally.
|
105
|
+
* Commit, do not mess with rakefile, version, or history.
|
106
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
107
|
+
* Send me a pull request. Bonus points for topic branches.
|
108
|
+
|
109
|
+
## Copyright
|
110
|
+
|
111
|
+
Copyright (c) 2010 Kristian Mandrup. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gem|
|
4
|
+
gem.name = "rspec_for_generators"
|
5
|
+
gem.summary = %Q{RSpec 2 matchers, helpers and utils for writing generator specs}
|
6
|
+
gem.description = %Q{RSpec 2 matchers, helpers and utils to assist in writing generator specs}
|
7
|
+
gem.email = "kmandrup@gmail.com"
|
8
|
+
gem.homepage = "http://github.com/kristianmandrup/rspec_for_generators"
|
9
|
+
gem.authors = ["Kristian Mandrup"]
|
10
|
+
gem.add_development_dependency "rspec", ">= 2.0.0.beta19"
|
11
|
+
gem.add_dependency "rspec", ">= 2.0.0.beta.19"
|
12
|
+
gem.add_dependency "rake", ">= 0.8.7"
|
13
|
+
gem.add_dependency "rails", ">= 3.0.0.rc"
|
14
|
+
gem.add_dependency "test-unit", ">= 2.0.9"
|
15
|
+
gem.add_dependency "require_all", ">= 1.1.0"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
# require 'spec/rake/spectask'
|
24
|
+
# Spec::Rake::SpecTask.new(:spec) do |spec|
|
25
|
+
# spec.libs << 'lib' << 'spec'
|
26
|
+
# spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
# spec.libs << 'lib' << 'spec'
|
31
|
+
# spec.pattern = 'spec/**/*_spec.rb'
|
32
|
+
# spec.rcov = true
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# task :spec => :check_dependencies
|
36
|
+
#
|
37
|
+
# task :default => :spec
|
38
|
+
#
|
39
|
+
# require 'rake/rdoctask'
|
40
|
+
# Rake::RDocTask.new do |rdoc|
|
41
|
+
# version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
#
|
43
|
+
# rdoc.rdoc_dir = 'rdoc'
|
44
|
+
# rdoc.title = "rspec_for_generators #{version}"
|
45
|
+
# rdoc.rdoc_files.include('README*')
|
46
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
# end
|
48
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class DemoGenerator < Rails::Generators::Base
|
2
|
+
desc "Adds Canable::Ables permission system to Model"
|
3
|
+
|
4
|
+
argument :name, :type => :string, :default => 'User', :desc => 'Name of model to make Canable:Able', :required => false
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.expand_path("../../templates", __FILE__)
|
8
|
+
end
|
9
|
+
|
10
|
+
def make_canable_able
|
11
|
+
if File.exist?(model_file_name)
|
12
|
+
@model_file_txt = File.open(model_file_name).read
|
13
|
+
after_txt = find_after_txt(model_file_txt)
|
14
|
+
inject_into_file(model_file_name, canable_include_txt, :after => after_txt) if after_txt
|
15
|
+
else
|
16
|
+
say "#{model_file_name} does not exist. Please create it first before you can make it Canable:Able", :red
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def post_log
|
21
|
+
say "Your model #{model_class_name} is now Canable:Able. Please define your permission login in #{model_file_name}", :green
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
attr_accessor :model_file_txt
|
27
|
+
|
28
|
+
def find_after_txt model_file_txt
|
29
|
+
# after first include statement
|
30
|
+
match = (model_file_txt =~ /(include\s+\S+)/)
|
31
|
+
return $1 if match
|
32
|
+
|
33
|
+
# or after class definition if no includes
|
34
|
+
match = model_file_txt =~ /(class\s+#{model_class_name}\s+<\s+ActiveRecord::Base)/ # first try match AR model
|
35
|
+
match = model_file_txt =~ /(class\s+#{model_class_name})/ if !match
|
36
|
+
$1 || nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def model_class_name
|
40
|
+
name.camelize
|
41
|
+
end
|
42
|
+
|
43
|
+
def model_file_name
|
44
|
+
File.join(Rails.root, "app/models/#{name}.rb")
|
45
|
+
end
|
46
|
+
|
47
|
+
def canable_include_txt
|
48
|
+
%Q{
|
49
|
+
include Canable::Ables
|
50
|
+
#{add_userstamps}
|
51
|
+
|
52
|
+
# permission logic
|
53
|
+
#{add_methods}
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def has_userstamps?
|
58
|
+
model_file_txt =~ /userstamps!/
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_userstamps
|
62
|
+
if !has_userstamps?
|
63
|
+
"userstamps! # adds creator and updater\n" if options[:userstamps]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_method? name
|
68
|
+
model_file_txt =~ /(def #{name}_by\?)/
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_methods
|
72
|
+
methods = []
|
73
|
+
%w{creatable destroyable updatable viewable}.each do |name|
|
74
|
+
if !has_method?(name)
|
75
|
+
method = add_method(name)
|
76
|
+
methods << method if method
|
77
|
+
end
|
78
|
+
end
|
79
|
+
methods.join("\n ")
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_method(name)
|
83
|
+
if options[name.to_sym]
|
84
|
+
%Q{
|
85
|
+
def #{name}_by?(user)
|
86
|
+
true
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'rake'
|
3
|
+
require 'rails'
|
4
|
+
require 'require_all'
|
5
|
+
require 'rails/generators'
|
6
|
+
require 'rspec_for_generators/main'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.include(RSpec::FileMatchers)
|
10
|
+
config.include(RSpec::RubyContentMatchers)
|
11
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rails/all'
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/test_case'
|
5
|
+
|
6
|
+
require 'rspec_for_generators/rails_spec_helper'
|
7
|
+
|
8
|
+
# Call configure to load the settings from
|
9
|
+
# Rails.application.config.generators to Rails::Generators
|
10
|
+
|
11
|
+
Rails::Generators.configure!
|
12
|
+
|
13
|
+
# require the generators
|
14
|
+
def require_generators generator_list
|
15
|
+
generator_list.each do |name, generators|
|
16
|
+
generators.each do |generator_name|
|
17
|
+
require File.join('generators', name.to_s, generator_name.to_s, "#{generator_name}_generator")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module RSpec
|
23
|
+
module Generator
|
24
|
+
class << self
|
25
|
+
attr_accessor :generator, :test_method_name
|
26
|
+
|
27
|
+
def run_generator *args, &block
|
28
|
+
generator.run_generator *args
|
29
|
+
if block
|
30
|
+
block.arity < 1 ? generator.instance_eval(&block) : block.call(generator, self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def check(&block)
|
35
|
+
if block
|
36
|
+
block.arity < 1 ? self.instance_eval(&block) : block.call(self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def with(generator, &block)
|
41
|
+
if block
|
42
|
+
block.arity < 1 ? generator.instance_eval(&block) : block.call(generator, self, generator.class)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def with_generator &block
|
47
|
+
with(get_generator, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def setup_generator test_method_name=nil, &block
|
51
|
+
clean! if test_method_name
|
52
|
+
generator = get_generator(test_method_name).extend(RSpec::Generator::Helpers)
|
53
|
+
if block
|
54
|
+
block.arity < 1 ? generator.class.instance_eval(&block) : block.call(generator.class)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def clean!
|
61
|
+
if generator
|
62
|
+
generator.class.generator_class = nil
|
63
|
+
end
|
64
|
+
@generator = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_generator test_method_name=nil
|
68
|
+
@generator ||= RSpec::Generators::TestCase.new(test_method_name + '_spec')
|
69
|
+
end
|
70
|
+
|
71
|
+
end # class self
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'rspec_for_generators/rails_spec_helper'
|
2
|
+
require 'rspec_for_generators/rspec_test_case'
|
3
|
+
require 'rspec_for_generators/generator_spec_helper'
|
4
|
+
|
5
|
+
require_all File.dirname(__FILE__) + '/matchers/helpers'
|
6
|
+
require_all File.dirname(__FILE__) + '/matchers/content'
|
7
|
+
require_all File.dirname(__FILE__) + '/matchers/file'
|
@@ -0,0 +1 @@
|
|
1
|
+
require_all File.dirname(__FILE__)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RSpec
|
2
|
+
module RubyContentMatchers
|
3
|
+
class HaveClass
|
4
|
+
|
5
|
+
attr_reader :klass
|
6
|
+
|
7
|
+
def initialize(klass)
|
8
|
+
@klass = klass
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(content)
|
12
|
+
@content = content
|
13
|
+
match_res = (@content =~ /class\s+#{@klass}\s+(.*)end/m)
|
14
|
+
if block_given? && $1
|
15
|
+
ruby_content = $1.strip.extend(RSpec::RubyContent::Helpers)
|
16
|
+
yield ruby_content
|
17
|
+
else
|
18
|
+
match_res
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def failure_message
|
23
|
+
"Expected there to be the class #{klass}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def negative_failure_message
|
27
|
+
"Did no expected there to be the class #{klass}"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def have_class(klass)
|
33
|
+
HaveClass.new(klass)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|