intersect_rails_composer 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.textile +433 -0
- data/bin/intersect_rails_composer +7 -0
- data/lib/rails_wizard/command.rb +204 -0
- data/lib/rails_wizard/config.rb +88 -0
- data/lib/rails_wizard/diagnostics.rb +68 -0
- data/lib/rails_wizard/recipe.rb +114 -0
- data/lib/rails_wizard/recipes.rb +56 -0
- data/lib/rails_wizard/template.rb +111 -0
- data/lib/rails_wizard.rb +7 -0
- data/recipes/apps4.rb +150 -0
- data/recipes/controllers.rb +75 -0
- data/recipes/core.rb +14 -0
- data/recipes/email.rb +110 -0
- data/recipes/example.rb +70 -0
- data/recipes/extras.rb +187 -0
- data/recipes/frontend.rb +45 -0
- data/recipes/gems.rb +277 -0
- data/recipes/git.rb +20 -0
- data/recipes/init.rb +136 -0
- data/recipes/models.rb +109 -0
- data/recipes/prelaunch.rb +119 -0
- data/recipes/railsapps.rb +277 -0
- data/recipes/readme.rb +85 -0
- data/recipes/routes.rb +45 -0
- data/recipes/saas.rb +218 -0
- data/recipes/setup.rb +134 -0
- data/recipes/testing.rb +276 -0
- data/recipes/views.rb +57 -0
- data/spec/rails_wizard/config_spec.rb +108 -0
- data/spec/rails_wizard/recipe_spec.rb +115 -0
- data/spec/rails_wizard/recipes/sanity_spec.rb +30 -0
- data/spec/rails_wizard/recipes_spec.rb +41 -0
- data/spec/rails_wizard/template_spec.rb +92 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/rails_directory.rb +17 -0
- data/spec/support/template_runner.rb +28 -0
- data/spec/test_recipes/test_recipe_in_file.rb +9 -0
- data/templates/helpers.erb +135 -0
- data/templates/layout.erb +232 -0
- data/templates/recipe.erb +13 -0
- data/version.rb +3 -0
- metadata +210 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsWizard::Recipe do
|
4
|
+
context "with a generated recipe" do
|
5
|
+
subject{ RailsWizard::Recipe.generate('recipe_example', "# this is a test", :category => 'example', :name => "RailsWizard Example") }
|
6
|
+
|
7
|
+
context 'string setter methods' do
|
8
|
+
(RailsWizard::Recipe::ATTRIBUTES - ['config']).each do |setter|
|
9
|
+
it "should be able to set #{setter} with an argument" do
|
10
|
+
subject.send(setter + '=', "test")
|
11
|
+
subject.send(setter).should == 'test'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should be able to get the value from the instance' do
|
15
|
+
subject.send(setter + '=', 'test')
|
16
|
+
subject.new.send(setter).should == subject.send(setter)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.attributes' do
|
22
|
+
it 'should be accessible from the instance' do
|
23
|
+
subject.new.attributes.should == subject.attributes
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '.generate' do
|
28
|
+
it 'should work with a string and hash as arguments' do
|
29
|
+
recipe = RailsWizard::Recipe.generate('some_key', '# some code', :name => "Example")
|
30
|
+
recipe.superclass.should == RailsWizard::Recipe
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should work with an IO object' do
|
34
|
+
file = StringIO.new <<-RUBY
|
35
|
+
# this is an example
|
36
|
+
|
37
|
+
__END__
|
38
|
+
|
39
|
+
category: example
|
40
|
+
name: This is an Example
|
41
|
+
description: You know it's an exmaple.
|
42
|
+
RUBY
|
43
|
+
recipe = RailsWizard::Recipe.generate('just_a_test', file)
|
44
|
+
recipe.template.should == '# this is an example'
|
45
|
+
recipe.category.should == 'example'
|
46
|
+
recipe.name.should == 'This is an Example'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should raise an exception if the file is incorrectly formatted' do
|
50
|
+
file = StringIO.new <<-RUBY
|
51
|
+
# just ruby, no YAML
|
52
|
+
RUBY
|
53
|
+
lambda{RailsWizard::Recipe.generate('testing',file)}.should raise_error(ArgumentError)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#compile' do
|
58
|
+
it 'should say the name' do
|
59
|
+
subject.name = "Awesome Sauce"
|
60
|
+
subject.new.compile.should be_include("say_recipe 'Awesome Sauce'")
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should include the template' do
|
64
|
+
subject.template = "This is only a test."
|
65
|
+
subject.new.compile.should be_include(subject.template)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should set default attributes' do
|
71
|
+
recipe = RailsWizard::Recipe.generate('abc','# test')
|
72
|
+
|
73
|
+
RailsWizard::Recipe::DEFAULT_ATTRIBUTES.each_pair do |k,v|
|
74
|
+
recipe.send(k).should == v
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe ".from_mongo" do
|
79
|
+
context "when asked for a known recipe" do
|
80
|
+
before(:all) do
|
81
|
+
@recipe_key = 'recipe_example'
|
82
|
+
@recipe = RailsWizard::Recipe.generate(@recipe_key, '# this is a test', {
|
83
|
+
:category => 'example',
|
84
|
+
:name => 'RailsWizard Example',
|
85
|
+
} )
|
86
|
+
RailsWizard::Recipes.add(@recipe)
|
87
|
+
@recipe_klass = Kernel.
|
88
|
+
const_get('RailsWizard' ).
|
89
|
+
const_get('Recipes' ).
|
90
|
+
const_get('RecipeExample')
|
91
|
+
end
|
92
|
+
|
93
|
+
context "by key" do
|
94
|
+
it "returns the recipe" do
|
95
|
+
RailsWizard::Recipe.from_mongo(@recipe_key).should == @recipe_klass
|
96
|
+
end
|
97
|
+
end
|
98
|
+
context "by class" do
|
99
|
+
it "returns the recipe" do
|
100
|
+
RailsWizard::Recipe.from_mongo(@recipe_klass).should == @recipe_klass
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "when asked for an unknown recipe" do
|
106
|
+
it "raises an UnknownRecipeError" do
|
107
|
+
expect { RailsWizard::Recipe.from_mongo("foo") }.to raise_error RailsWizard::UnknownRecipeError, "No recipe found with name 'foo'"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
__END__
|
114
|
+
|
115
|
+
this is a test
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# This is a simple set of tests to make sure that
|
4
|
+
# all of the recipes conform to the base requirements.
|
5
|
+
|
6
|
+
RailsWizard::Recipes.list_classes.each do |recipe|
|
7
|
+
describe recipe do
|
8
|
+
it("should have a name"){ recipe.name.should be_kind_of(String) }
|
9
|
+
it("should have a description"){ recipe.description.should be_kind_of(String) }
|
10
|
+
it("should have a template"){ recipe.template.should be_kind_of(String) }
|
11
|
+
it("should be able to compile"){ recipe.new.compile.should be_kind_of(String) }
|
12
|
+
|
13
|
+
it "should have a string or nil category" do
|
14
|
+
if recipe.category
|
15
|
+
recipe.category.should be_kind_of(String)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have a Config or nil config" do
|
20
|
+
if recipe.config
|
21
|
+
recipe.config.should be_kind_of(RailsWizard::Config)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be in the list" do
|
26
|
+
RailsWizard::Recipes.list_classes.should be_include(recipe)
|
27
|
+
RailsWizard::Recipes.list.should be_include(recipe.key)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsWizard::Recipes do
|
4
|
+
subject{ RailsWizard::Recipes }
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@recipe = RailsWizard::Recipe.generate( "recipe_test", "# Testing", {
|
8
|
+
:category => 'test',
|
9
|
+
:description => 'Just a test.',
|
10
|
+
:name => 'Test Recipe',
|
11
|
+
} )
|
12
|
+
RailsWizard::Recipes.add(@recipe)
|
13
|
+
end
|
14
|
+
|
15
|
+
it '.list_classes should include recipe classes' do
|
16
|
+
subject.list_classes.should be_include(@recipe)
|
17
|
+
end
|
18
|
+
|
19
|
+
it '.list should include recipe keys' do
|
20
|
+
subject.list.should be_include('recipe_test')
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.for' do
|
24
|
+
it 'should find for a given category' do
|
25
|
+
RailsWizard::Recipes.for('test').should be_include('recipe_test')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should add recipes in a directory with add_from_directory' do
|
30
|
+
subject.add_from_directory(File.join(File.dirname(__FILE__), '..', 'test_recipes'))
|
31
|
+
subject.list.should include 'test_recipe_in_file'
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.clear' do
|
35
|
+
it 'should remove all current recipes' do
|
36
|
+
RailsWizard::Recipes.clear
|
37
|
+
subject.list.should == []
|
38
|
+
subject.categories.should == []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsWizard::Template do
|
4
|
+
subject{ RailsWizard::Template }
|
5
|
+
let(:recipe){ RailsWizard::Recipe.generate('name','# test') }
|
6
|
+
let(:defaults){ { "some_option" => "value" } }
|
7
|
+
let(:gems){ ['foogem'] }
|
8
|
+
let(:args){ [] }
|
9
|
+
|
10
|
+
describe '.template_root' do
|
11
|
+
it 'returns the gem ./templates directory by default' do
|
12
|
+
template_root = File.expand_path(subject.template_root)
|
13
|
+
template_root.should == File.expand_path('../../../templates', __FILE__)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can be set to another directory' do
|
17
|
+
subject.template_root = '/tmp/templates'
|
18
|
+
subject.template_root.should == '/tmp/templates'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#initialize' do
|
23
|
+
it 'should work with classes' do
|
24
|
+
subject.new([recipe], gems).recipes.should == [recipe]
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should accept optional defaults' do
|
28
|
+
subject.new([recipe], gems, args, defaults).defaults.should == defaults
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#resolve_dependencies' do
|
33
|
+
def recipe(name, opts={})
|
34
|
+
RailsWizard::Recipe.generate(name, '', opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
subject do
|
38
|
+
@template = RailsWizard::Template.new([])
|
39
|
+
@template.stub(:recipes_with_dependencies).and_return(@recipes)
|
40
|
+
@template.resolve_recipes.map { |r| r.key }
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should sort properly' do
|
44
|
+
@recipes = [
|
45
|
+
recipe('add_user', :run_after => ['devise']),
|
46
|
+
recipe('devise', :run_after => ['omniauth']),
|
47
|
+
recipe('omniauth'),
|
48
|
+
recipe('haml'),
|
49
|
+
recipe('compass')
|
50
|
+
]
|
51
|
+
|
52
|
+
subject.index('devise').should > subject.index('omniauth')
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#recipes_with_dependencies' do
|
58
|
+
def r(*deps)
|
59
|
+
double(:Class, :requires => deps, :superclass => RailsWizard::Recipe)
|
60
|
+
end
|
61
|
+
|
62
|
+
subject do
|
63
|
+
@template = RailsWizard::Template.new([])
|
64
|
+
@template.stub(:recipes).and_return(@recipes)
|
65
|
+
@template.stub(:recipe_classes).and_return(@recipes)
|
66
|
+
@template
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return the same number recipes if none have dependencies' do
|
70
|
+
@recipes = [r, r]
|
71
|
+
subject.recipes_with_dependencies.size.should == 2
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should handle simple dependencies' do
|
75
|
+
@recipes = [r(r, r), r(r)]
|
76
|
+
subject.recipes_with_dependencies.size.should == 5
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should handle multi-level dependencies' do
|
80
|
+
@recipes = [r(r(r))]
|
81
|
+
subject.recipes_with_dependencies.size.should == 3
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should uniqify' do
|
85
|
+
a = r
|
86
|
+
b = r(a)
|
87
|
+
c = r(r, a, b)
|
88
|
+
@recipes = [a,b,c]
|
89
|
+
subject.recipes_with_dependencies.size.should == 4
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class RailsDirectory
|
2
|
+
def initialize(path)
|
3
|
+
@path = path
|
4
|
+
end
|
5
|
+
|
6
|
+
def file_path(path)
|
7
|
+
File.join(@path, path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_file?(path)
|
11
|
+
File.exist?(file_path(path))
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](path)
|
15
|
+
File.open(file_path(path)).read
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class TemplateRunner
|
2
|
+
attr_reader :template, :config, :app_name, :dir, :rails_dir, :output
|
3
|
+
def initialize(template, config)
|
4
|
+
@template = template
|
5
|
+
@config = config
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(app_name = 'rails_app')
|
9
|
+
@app_name = app_name
|
10
|
+
@dir = Dir.mktmpdir
|
11
|
+
@rails_dir = File.join(@dir, @app_name)
|
12
|
+
Dir.chrdir(@dir) do
|
13
|
+
template_file = File.open 'template.rb', 'w'
|
14
|
+
template_file.write
|
15
|
+
template_file.close
|
16
|
+
@output = `rails new #{@app_name} -m template.rb`
|
17
|
+
end
|
18
|
+
@output
|
19
|
+
end
|
20
|
+
|
21
|
+
def rails
|
22
|
+
RailsDirectory.new(@rails_dir)
|
23
|
+
end
|
24
|
+
|
25
|
+
def clean
|
26
|
+
FileUtils.remove_entry_secure @dir
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
def recipes; @recipes end
|
2
|
+
def recipe?(name); @recipes.include?(name) end
|
3
|
+
def prefs; @prefs end
|
4
|
+
def prefer(key, value); @prefs[key].eql? value end
|
5
|
+
def gems; @gems end
|
6
|
+
def diagnostics_recipes; @diagnostics_recipes end
|
7
|
+
def diagnostics_prefs; @diagnostics_prefs end
|
8
|
+
|
9
|
+
def say_custom(tag, text); say "\033[1m\033[36m" + tag.to_s.rjust(10) + "\033[0m" + " #{text}" end
|
10
|
+
def say_recipe(name); say "\033[1m\033[36m" + "recipe".rjust(10) + "\033[0m" + " Running #{name} recipe..." end
|
11
|
+
def say_wizard(text); say_custom(@current_recipe || 'composer', text) end
|
12
|
+
|
13
|
+
def rails_4?
|
14
|
+
Rails::VERSION::MAJOR.to_s == "4"
|
15
|
+
end
|
16
|
+
|
17
|
+
def ask_wizard(question)
|
18
|
+
ask "\033[1m\033[36m" + (@current_recipe || "prompt").rjust(10) + "\033[1m\033[36m" + " #{question}\033[0m"
|
19
|
+
end
|
20
|
+
|
21
|
+
def yes_wizard?(question)
|
22
|
+
answer = ask_wizard(question + " \033[33m(y/n)\033[0m")
|
23
|
+
case answer.downcase
|
24
|
+
when "yes", "y"
|
25
|
+
true
|
26
|
+
when "no", "n"
|
27
|
+
false
|
28
|
+
else
|
29
|
+
yes_wizard?(question)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def no_wizard?(question); !yes_wizard?(question) end
|
34
|
+
|
35
|
+
def multiple_choice(question, choices)
|
36
|
+
say_custom('question', question)
|
37
|
+
values = {}
|
38
|
+
choices.each_with_index do |choice,i|
|
39
|
+
values[(i + 1).to_s] = choice[1]
|
40
|
+
say_custom( (i + 1).to_s + ')', choice[0] )
|
41
|
+
end
|
42
|
+
answer = ask_wizard("Enter your selection:") while !values.keys.include?(answer)
|
43
|
+
values[answer]
|
44
|
+
end
|
45
|
+
|
46
|
+
@current_recipe = nil
|
47
|
+
@configs = {}
|
48
|
+
|
49
|
+
@after_blocks = []
|
50
|
+
def after_bundler(&block); @after_blocks << [@current_recipe, block]; end
|
51
|
+
@after_everything_blocks = []
|
52
|
+
def after_everything(&block); @after_everything_blocks << [@current_recipe, block]; end
|
53
|
+
@before_configs = {}
|
54
|
+
def before_config(&block); @before_configs[@current_recipe] = block; end
|
55
|
+
|
56
|
+
def copy_from(source, destination)
|
57
|
+
begin
|
58
|
+
remove_file destination
|
59
|
+
get source, destination
|
60
|
+
rescue OpenURI::HTTPError
|
61
|
+
say_wizard "Unable to obtain #{source}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def copy_from_repo(filename, opts = {})
|
66
|
+
repo = 'https://raw.github.com/IntersectAustralia/rails-composer/master/files/'
|
67
|
+
repo = opts[:repo] unless opts[:repo].nil?
|
68
|
+
if (!opts[:prefs].nil?) && (!prefs.has_value? opts[:prefs])
|
69
|
+
return
|
70
|
+
end
|
71
|
+
source_filename = filename
|
72
|
+
destination_filename = filename
|
73
|
+
unless opts[:prefs].nil?
|
74
|
+
if filename.include? opts[:prefs]
|
75
|
+
destination_filename = filename.gsub(/\-#{opts[:prefs]}/, '')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if (prefer :templates, 'haml') && (filename.include? 'views')
|
79
|
+
remove_file destination_filename
|
80
|
+
destination_filename = destination_filename.gsub(/.erb/, '.haml')
|
81
|
+
end
|
82
|
+
if (prefer :templates, 'slim') && (filename.include? 'views')
|
83
|
+
remove_file destination_filename
|
84
|
+
destination_filename = destination_filename.gsub(/.erb/, '.slim')
|
85
|
+
end
|
86
|
+
begin
|
87
|
+
remove_file destination_filename
|
88
|
+
if (prefer :templates, 'haml') && (filename.include? 'views')
|
89
|
+
create_file destination_filename, html_to_haml(repo + source_filename)
|
90
|
+
elsif (prefer :templates, 'slim') && (filename.include? 'views')
|
91
|
+
create_file destination_filename, html_to_slim(repo + source_filename)
|
92
|
+
else
|
93
|
+
get repo + source_filename, destination_filename
|
94
|
+
end
|
95
|
+
rescue OpenURI::HTTPError
|
96
|
+
say_wizard "Unable to obtain #{source_filename} from the repo #{repo}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def html_to_haml(source)
|
101
|
+
begin
|
102
|
+
html = open(source) {|input| input.binmode.read }
|
103
|
+
Haml::HTML.new(html, :erb => true, :xhtml => true).render
|
104
|
+
rescue RubyParser::SyntaxError
|
105
|
+
say_wizard "Ignoring RubyParser::SyntaxError"
|
106
|
+
# special case to accommodate https://github.com/RailsApps/rails-composer/issues/55
|
107
|
+
html = open(source) {|input| input.binmode.read }
|
108
|
+
say_wizard "applying patch" if html.include? 'card_month'
|
109
|
+
say_wizard "applying patch" if html.include? 'card_year'
|
110
|
+
html = html.gsub(/, {add_month_numbers: true}, {name: nil, id: "card_month"}/, '')
|
111
|
+
html = html.gsub(/, {start_year: Date\.today\.year, end_year: Date\.today\.year\+10}, {name: nil, id: "card_year"}/, '')
|
112
|
+
result = Haml::HTML.new(html, :erb => true, :xhtml => true).render
|
113
|
+
result = result.gsub(/select_month nil/, "select_month nil, {add_month_numbers: true}, {name: nil, id: \"card_month\"}")
|
114
|
+
result = result.gsub(/select_year nil/, "select_year nil, {start_year: Date.today.year, end_year: Date.today.year+10}, {name: nil, id: \"card_year\"}")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def html_to_slim(source)
|
119
|
+
html = open(source) {|input| input.binmode.read }
|
120
|
+
haml = Haml::HTML.new(html, :erb => true, :xhtml => true).render
|
121
|
+
Haml2Slim.convert!(haml)
|
122
|
+
end
|
123
|
+
|
124
|
+
# full credit to @mislav in this StackOverflow answer for the #which() method:
|
125
|
+
# - http://stackoverflow.com/a/5471032
|
126
|
+
def which(cmd)
|
127
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
128
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
129
|
+
exts.each do |ext|
|
130
|
+
exe = "#{path}#{File::SEPARATOR}#{cmd}#{ext}"
|
131
|
+
return exe if File.executable? exe
|
132
|
+
end
|
133
|
+
end
|
134
|
+
return nil
|
135
|
+
end
|