rails3_devise_wizard 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +135 -0
- data/bin/rails3_devise_wizard +7 -0
- data/lib/rails_wizard/command.rb +79 -0
- data/lib/rails_wizard/config.rb +86 -0
- data/lib/rails_wizard/recipe.rb +106 -0
- data/lib/rails_wizard/recipes.rb +38 -0
- data/lib/rails_wizard/template.rb +58 -0
- data/lib/rails_wizard.rb +10 -0
- data/recipes/action_mailer.rb +41 -0
- data/recipes/activerecord.rb +37 -0
- data/recipes/add_user_name.rb +75 -0
- data/recipes/application_layout.rb +43 -0
- data/recipes/ban_spiders.rb +19 -0
- data/recipes/capybara.rb +34 -0
- data/recipes/cleanup.rb +34 -0
- data/recipes/css_setup.rb +40 -0
- data/recipes/cucumber.rb +69 -0
- data/recipes/devise.rb +35 -0
- data/recipes/devise_navigation.rb +95 -0
- data/recipes/env_yaml.rb +54 -0
- data/recipes/git.rb +26 -0
- data/recipes/haml.rb +14 -0
- data/recipes/heroku.rb +58 -0
- data/recipes/home_page.rb +43 -0
- data/recipes/home_page_users.rb +50 -0
- data/recipes/hoptoad.rb +34 -0
- data/recipes/jammit.rb +43 -0
- data/recipes/jquery.rb +44 -0
- data/recipes/less.rb +12 -0
- data/recipes/mongo_mapper.rb +18 -0
- data/recipes/mongohq.rb +59 -0
- data/recipes/mongoid.rb +30 -0
- data/recipes/mootools.rb +23 -0
- data/recipes/omniauth.rb +15 -0
- data/recipes/pow.rb +12 -0
- data/recipes/prototype.rb +11 -0
- data/recipes/rails_admin.rb +21 -0
- data/recipes/redis.rb +17 -0
- data/recipes/redistogo.rb +40 -0
- data/recipes/rightjs.rb +17 -0
- data/recipes/rspec.rb +89 -0
- data/recipes/sass.rb +13 -0
- data/recipes/seed_database.rb +35 -0
- data/recipes/sequel.rb +13 -0
- data/recipes/settingslogic.rb +43 -0
- data/recipes/slim.rb +11 -0
- data/recipes/test_unit.rb +11 -0
- data/recipes/users_page.rb +103 -0
- data/spec/rails_wizard/config_spec.rb +99 -0
- data/spec/rails_wizard/recipe_spec.rb +103 -0
- data/spec/rails_wizard/recipes/sanity_spec.rb +30 -0
- data/spec/rails_wizard/recipes_spec.rb +24 -0
- data/spec/rails_wizard/template_spec.rb +48 -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/templates/helpers.erb +45 -0
- data/templates/layout.erb +46 -0
- data/templates/recipe.erb +10 -0
- data/version.rb +3 -0
- metadata +205 -0
data/README.textile
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
h1. Rails3 Devise Wizard Gem
|
2
|
+
|
3
|
+
A gem to create a ready-to-run Rails web application you can deploy in minutes.
|
4
|
+
|
5
|
+
This gem can be used to create the "rails3-mongoid-devise":http://github.com/fortuity/rails3-mongoid-devise/ example application, as described in a detailed "tutorial":http://github.com/fortuity/rails3-mongoid-devise/wiki/Tutorial-%28Walkthrough%29.
|
6
|
+
|
7
|
+
h2. Based on Michael Bleigh's RailsWizard Gem
|
8
|
+
|
9
|
+
The rails3_devise_wizard gem is a fork of "Michael Bleigh's RailsWizard gem":https://github.com/intridea/rails_wizard (see credits below). The purpose of this fork is to provide recipes for a ready-to-run Rails web application that uses Devise for authentication.
|
10
|
+
|
11
|
+
h2. Dependencies
|
12
|
+
|
13
|
+
Before generating a new Rails app using an application template, you will need:
|
14
|
+
|
15
|
+
* The Ruby language (version 1.8.7 or 1.9.2)
|
16
|
+
* Rails (version 3.0.4 or newer)
|
17
|
+
|
18
|
+
I recommend installing rvm, the "Ruby Version Manager":http://rvm.beginrescueend.com/, to manage multiple versions of Rails.
|
19
|
+
|
20
|
+
If you are using rvm, you can see a list of the Ruby versions currently installed:
|
21
|
+
@$ rvm list@
|
22
|
+
|
23
|
+
Check that appropriate versions of Ruby and Rails are installed in your development environment:
|
24
|
+
@$ ruby -v@
|
25
|
+
@$ rails -v@
|
26
|
+
|
27
|
+
h2. Installation
|
28
|
+
|
29
|
+
Installation is simple:
|
30
|
+
|
31
|
+
bc. gem install rails3_devise_wizard, :git => 'git://github.com/fortuity/rails3_devise_wizard.git'
|
32
|
+
|
33
|
+
|
34
|
+
h2. Usage
|
35
|
+
|
36
|
+
The @rails3_devise_wizard@ gem offers an interactive terminal command to build a Rails application template. To get started, run:
|
37
|
+
|
38
|
+
bc. rails3_devise_wizard new APP_NAME
|
39
|
+
|
40
|
+
|
41
|
+
Where @APP_NAME@ is the directory in which you wish to create the app (it mirrors the Rails creation syntax). You will then be guided through the recipe selection process and subsequently the Rails app generator will automatically run with the template and all appropriate command line options included.
|
42
|
+
|
43
|
+
h4. Specifying Recipes
|
44
|
+
|
45
|
+
If you wish to skip the interactive recipe selector, you may provide instead a list of recipes with the @-r@ option:
|
46
|
+
|
47
|
+
bc. rails3_devise_wizard new APP_NAME -r jquery mongo_mapper sass
|
48
|
+
|
49
|
+
|
50
|
+
This will automatically generate a Rails template with the provided recipes and launch the app generator.
|
51
|
+
|
52
|
+
h4. Listing Recipes
|
53
|
+
|
54
|
+
You can also print out a simple list of recipes:
|
55
|
+
|
56
|
+
bc. rails3_devise_wizard list
|
57
|
+
|
58
|
+
|
59
|
+
Or print out a list of recipes for a specific category:
|
60
|
+
|
61
|
+
bc. rails3_devise_wizard list persistence
|
62
|
+
|
63
|
+
|
64
|
+
h2. Rails3 Devise Wizard Recipes
|
65
|
+
|
66
|
+
You can find the rails3_devise_wizard recipe collection in the GitHub repository's "recipes directory":https://github.com/fortuity/rails3_devise_wizard/tree/master/recipes. If you find errors or fork a recipe you can submit a pull request or create a "Github issue":http://github.com/fortuity/rails3_devise_wizard/issues.
|
67
|
+
|
68
|
+
h4. Writing New Recipes
|
69
|
+
|
70
|
+
Recipes are made of up *template code* and *YAML back-matter* stored in a ruby file. The @__END__@ parsing convention is used so that each recipe is actually a valid, parseable Ruby file. The structure of a recipe looks something like this:
|
71
|
+
|
72
|
+
<pre>
|
73
|
+
gem 'supergem'
|
74
|
+
|
75
|
+
after_bundler do
|
76
|
+
generate "supergem:install"
|
77
|
+
end
|
78
|
+
|
79
|
+
__END__
|
80
|
+
|
81
|
+
category: templating
|
82
|
+
name: SuperGem
|
83
|
+
description: Installs SuperGem which is useful for things
|
84
|
+
author: mbleigh
|
85
|
+
</pre>
|
86
|
+
|
87
|
+
The gem has RSpec tests that automatically validate each recipe in the repository, so you should run @rake spec@ as a basic sanity check before submitting a pull request. Note that these don't verify that your recipe code itself works, just that the gem could properly parse and understand your recipe file.
|
88
|
+
|
89
|
+
For more information on all available options for authoring recipes, please see the "wiki for Michael Bleigh's RailsWizard gem":https://github.com/intridea/rails_wizard/wiki.
|
90
|
+
|
91
|
+
h2. How It Works
|
92
|
+
|
93
|
+
Rails generators can use any methods provided by the "Thor::Actions":http://rdoc.info/github/wycats/thor/master/Thor/Actions module. The flexibility of mixing "recipes" for application templates comes from use of the @apply@ method from the Thor::Actions module. Given a web address or a local filepath, the "apply method":http://rdoc.info/github/wycats/thor/master/Thor/Actions#apply-instance_method loads and executes a file within the context of the generator script.
|
94
|
+
|
95
|
+
h2. Documentation and Support
|
96
|
+
|
97
|
+
This is the only documentation.
|
98
|
+
|
99
|
+
h4. Writing Recipes
|
100
|
+
|
101
|
+
To understand the code in these templates, take a look at "Thor::Actions":http://rdoc.info/github/wycats/thor/master/Thor/Actions. Your recipes can use any methods provided by "Thor::Actions":http://rdoc.info/github/wycats/thor/master/Thor/Actions or "Rails::Generators::Actions":http://railsapi.com/doc/rails-v3.0.3/classes/Rails/Generators/Actions.html.
|
102
|
+
|
103
|
+
Please send a message (via GitHub) or a "pull request" if you've written recipes you'd like to contribute.
|
104
|
+
|
105
|
+
h4. About Rails Application Templates
|
106
|
+
|
107
|
+
"Cooking Up A Custom Rails 3 Template (11 Oct 2010) by Andrea Singh":http://blog.madebydna.com/all/code/2010/10/11/cooking-up-a-custom-rails3-template.html
|
108
|
+
"Rails Application Templates (16 Sept 2010) by Collin Schaafsma":http://quickleft.com/blog/rails-application-templates
|
109
|
+
"Application templates in Rails 3 (18 Sept 2009) by Ben Scofield":http://benscofield.com/2009/09/application-templates-in-rails-3/
|
110
|
+
"Railscasts: App Templates in Rails 2.3 (9 Feb 2009) by Ryan Bates":http://railscasts.com/episodes/148-app-templates-in-rails-2-3
|
111
|
+
"Rails templates (4 Dec 2008) by Pratik Naik":http://m.onkey.org/rails-templates
|
112
|
+
|
113
|
+
h2. Issues
|
114
|
+
|
115
|
+
Any issues? Please create a "GitHub issue":http://github.com/fortuity/rails3_devise_wizard/issues.
|
116
|
+
|
117
|
+
h2. Credits
|
118
|
+
|
119
|
+
This project is based on "Michael Bleigh's RailsWizard gem":https://github.com/intridea/rails_wizard. The original idea for a RailsWizard and the innovative implementation is the work of Michael Bleigh.
|
120
|
+
|
121
|
+
"Fletcher Nichol's":http://silversky.ca/ project "fnichol/rails-template-recipes":https://github.com/fnichol/rails-template-recipes provides the basis for several recipes.
|
122
|
+
|
123
|
+
RSpec, Cucumber, and Yard recipes were contributed by "Ramon Brooker":http://cogniton-mind.tumblr.com/.
|
124
|
+
|
125
|
+
Additional recipes by me, Daniel Kehoe "http://danielkehoe.com/":http://danielkehoe.com/, to implement the "rails3-mongoid-devise":http://github.com/fortuity/rails3-mongoid-devise/ example application.
|
126
|
+
|
127
|
+
Is the gem useful to you? Follow me on Twitter:
|
128
|
+
"http://twitter.com/railsinit":http://twitter.com/railsinit
|
129
|
+
and tweet some praise. I'd love to know you were helped out by the gem.
|
130
|
+
|
131
|
+
h2. License
|
132
|
+
|
133
|
+
h4. MIT License
|
134
|
+
|
135
|
+
The rails3_devise_wizard gem and its recipes are distributed under the MIT License.
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rails_wizard'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module RailsWizard
|
5
|
+
class Command < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
desc "new APP_NAME", "create a new Rails app"
|
8
|
+
method_option :recipes, :type => :array, :aliases => "-r"
|
9
|
+
def new(name)
|
10
|
+
if options[:recipes]
|
11
|
+
run_template(name, options[:recipes])
|
12
|
+
else
|
13
|
+
@recipes = []
|
14
|
+
|
15
|
+
while recipe = ask("#{print_recipes}#{bold}Which recipe would you like to add? #{clear}#{yellow}(blank to finish)#{clear}")
|
16
|
+
if recipe == ''
|
17
|
+
run_template(name, @recipes)
|
18
|
+
break
|
19
|
+
elsif RailsWizard::Recipes.list.include?(recipe)
|
20
|
+
@recipes << recipe
|
21
|
+
puts
|
22
|
+
puts "> #{green}Added '#{recipe}' to template.#{clear}"
|
23
|
+
else
|
24
|
+
puts
|
25
|
+
puts "> #{red}Invalid recipe, please try again.#{clear}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "list [CATEGORY]", "list available recipes (optionally by category)"
|
32
|
+
def list(category = nil)
|
33
|
+
if category
|
34
|
+
recipes = RailsWizard::Recipes.for(category).map{|r| RailsWizard::Recipe.from_mongo(r) }
|
35
|
+
else
|
36
|
+
recipes = RailsWizard::Recipes.list_classes
|
37
|
+
end
|
38
|
+
|
39
|
+
recipes.each do |recipe|
|
40
|
+
puts recipe.key.ljust(15) + "# #{recipe.description}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
no_tasks do
|
45
|
+
def cyan; "\033[36m" end
|
46
|
+
def clear; "\033[0m" end
|
47
|
+
def bold; "\033[1m" end
|
48
|
+
def red; "\033[31m" end
|
49
|
+
def green; "\033[32m" end
|
50
|
+
def yellow; "\033[33m" end
|
51
|
+
|
52
|
+
def print_recipes
|
53
|
+
puts
|
54
|
+
puts
|
55
|
+
puts
|
56
|
+
if @recipes && @recipes.any?
|
57
|
+
puts "#{green}#{bold}Your Recipes:#{clear} " + @recipes.join(", ")
|
58
|
+
puts
|
59
|
+
end
|
60
|
+
puts "#{bold}#{cyan}Available Recipes:#{clear} " + RailsWizard::Recipes.list.join(', ')
|
61
|
+
puts
|
62
|
+
end
|
63
|
+
|
64
|
+
def run_template(name, recipes)
|
65
|
+
puts
|
66
|
+
puts
|
67
|
+
puts "#{bold}Generating and Running Template..."
|
68
|
+
puts
|
69
|
+
file = Tempfile.new('template')
|
70
|
+
template = RailsWizard::Template.new(recipes)
|
71
|
+
file.write template.compile
|
72
|
+
file.close
|
73
|
+
system "rails new #{name} -m #{file.path} #{template.args.join(' ')}"
|
74
|
+
ensure
|
75
|
+
file.unlink
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'active_support/ordered_hash'
|
2
|
+
|
3
|
+
module RailsWizard
|
4
|
+
class Config
|
5
|
+
attr_reader :questions
|
6
|
+
|
7
|
+
def initialize(schema)
|
8
|
+
@questions = ActiveSupport::OrderedHash.new
|
9
|
+
schema.each do |hash|
|
10
|
+
key = hash.keys.first
|
11
|
+
details = hash.values.first
|
12
|
+
|
13
|
+
kind = details['type']
|
14
|
+
raise ArgumentError, "Unrecognized question type, must be one of #{QUESTION_TYPES.keys.join(', ')}" unless QUESTION_TYPES.keys.include?(kind)
|
15
|
+
@questions[key] = QUESTION_TYPES[kind].new(details)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def compile(values = {})
|
20
|
+
result = []
|
21
|
+
result << "config = #{values.inspect}"
|
22
|
+
@questions.each_pair do |key, question|
|
23
|
+
result << "config['#{key}'] = #{question.compile} unless config.key?('#{key}')"
|
24
|
+
end
|
25
|
+
result.join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
class Prompt
|
29
|
+
attr_reader :prompt, :details
|
30
|
+
def initialize(details)
|
31
|
+
@details = details
|
32
|
+
@prompt = details['prompt']
|
33
|
+
end
|
34
|
+
|
35
|
+
def compile
|
36
|
+
"#{question} if #{conditions}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def question
|
40
|
+
"ask_wizard(#{prompt.inspect})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def conditions
|
44
|
+
[config_conditions, recipe_conditions].join(' && ')
|
45
|
+
end
|
46
|
+
|
47
|
+
def config_conditions
|
48
|
+
if details['if']
|
49
|
+
"config['#{details['if']}']"
|
50
|
+
elsif details['unless']
|
51
|
+
"!config['#{details['unless']}']"
|
52
|
+
else
|
53
|
+
'true'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def recipe_conditions
|
58
|
+
if details['if_recipe']
|
59
|
+
"recipe?('#{details['if_recipe']}')"
|
60
|
+
elsif details['unless_recipe']
|
61
|
+
"!recipe?('#{details['unless_recipe']}')"
|
62
|
+
else
|
63
|
+
'true'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class TrueFalse < Prompt
|
69
|
+
def question
|
70
|
+
"yes_wizard?(#{prompt.inspect})"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class MultipleChoice < Prompt
|
75
|
+
def question
|
76
|
+
"multiple_choice(#{prompt.inspect}, #{@details['choices'].inspect})"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
QUESTION_TYPES = {
|
81
|
+
'boolean' => TrueFalse,
|
82
|
+
'string' => Prompt,
|
83
|
+
'multiple_choice' => MultipleChoice
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rails_wizard/config'
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'yaml'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
module RailsWizard
|
8
|
+
class Recipe
|
9
|
+
extend Comparable
|
10
|
+
|
11
|
+
def self.<=>(another)
|
12
|
+
return -1 if another.run_after.include?(self.key) || self.run_before.include?(another.key)
|
13
|
+
return 1 if another.run_before.include?(self.key) || self.run_after.include?(another.key)
|
14
|
+
self.key <=> another.key
|
15
|
+
end
|
16
|
+
|
17
|
+
ATTRIBUTES = %w(key args category name description template config exclusive tags run_before run_after requires)
|
18
|
+
DEFAULT_ATTRIBUTES = {
|
19
|
+
:category => 'other',
|
20
|
+
:args => [],
|
21
|
+
:tags => [],
|
22
|
+
:run_after => [],
|
23
|
+
:run_before => [],
|
24
|
+
:requires => []
|
25
|
+
}
|
26
|
+
|
27
|
+
def self.generate(key, template_or_file, attributes = {})
|
28
|
+
if template_or_file.respond_to?(:read)
|
29
|
+
file = template_or_file.read
|
30
|
+
parts = file.split(/^__END__$/)
|
31
|
+
raise ArgumentError, "The recipe file must have YAML matter after an __END__" unless parts.size == 2
|
32
|
+
template = parts.first.strip
|
33
|
+
attributes = YAML.load(parts.last).inject({}) do |h,(k,v)|
|
34
|
+
h[k.to_sym] = v
|
35
|
+
h
|
36
|
+
end.merge!(attributes)
|
37
|
+
else
|
38
|
+
template = template_or_file
|
39
|
+
end
|
40
|
+
|
41
|
+
recipe_class = Class.new(RailsWizard::Recipe)
|
42
|
+
recipe_class.attributes = attributes
|
43
|
+
recipe_class.template = template
|
44
|
+
recipe_class.key = key
|
45
|
+
|
46
|
+
recipe_class
|
47
|
+
end
|
48
|
+
|
49
|
+
ATTRIBUTES.each do |setter|
|
50
|
+
class_eval <<-RUBY
|
51
|
+
def self.#{setter}
|
52
|
+
attributes[:#{setter}]
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.#{setter}=(val)
|
56
|
+
attributes[:#{setter}] = val
|
57
|
+
end
|
58
|
+
|
59
|
+
def #{setter}
|
60
|
+
self.class.#{setter}
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
end
|
64
|
+
|
65
|
+
# The attributes hash containing any set values for
|
66
|
+
def self.attributes
|
67
|
+
@attributes ||= DEFAULT_ATTRIBUTES.dup
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.attributes=(hash)
|
71
|
+
attributes.merge! hash
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.config
|
75
|
+
return nil unless attributes[:config]
|
76
|
+
RailsWizard::Config.new(attributes[:config])
|
77
|
+
end
|
78
|
+
|
79
|
+
def attributes
|
80
|
+
self.class.attributes
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.compile
|
84
|
+
"# >#{"[ #{name} ]".center(75,'-')}<\n\n# #{description}\nsay_recipe '#{name}'\n\n#{template}\n"
|
85
|
+
end
|
86
|
+
def compile; self.class.compile end
|
87
|
+
|
88
|
+
def self.to_mongo(value)
|
89
|
+
case value
|
90
|
+
when Class
|
91
|
+
value.key
|
92
|
+
when String
|
93
|
+
value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.from_mongo(key)
|
98
|
+
return key if key.respond_to?(:superclass) && key.superclass == RailsWizard::Recipe
|
99
|
+
RailsWizard::Recipes[key]
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.get_binding
|
103
|
+
binding
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RailsWizard
|
2
|
+
module Recipes
|
3
|
+
@@categories = {}
|
4
|
+
@@list = {}
|
5
|
+
|
6
|
+
def self.add(recipe)
|
7
|
+
RailsWizard::Recipes.const_set ActiveSupport::Inflector.camelize(recipe.key), recipe
|
8
|
+
@@list[recipe.key] = recipe
|
9
|
+
(@@categories[recipe.category.to_s] ||= []) << recipe.key
|
10
|
+
@@categories[recipe.category.to_s].uniq!
|
11
|
+
recipe
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.[](key)
|
15
|
+
@@list[key.to_s]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.list
|
19
|
+
@@list.keys.sort
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.list_classes
|
23
|
+
@@list.values.sort_by{|c| c.key}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.categories
|
27
|
+
@@categories.keys.sort
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.for(category)
|
31
|
+
(@@categories[category.to_s] || []).sort
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.remove_from_category(category, recipe)
|
35
|
+
(@@categories[category.to_s] ||= []).delete(recipe.key)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|