rails3_devise_wizard 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/README.textile +135 -0
  2. data/bin/rails3_devise_wizard +7 -0
  3. data/lib/rails_wizard/command.rb +79 -0
  4. data/lib/rails_wizard/config.rb +86 -0
  5. data/lib/rails_wizard/recipe.rb +106 -0
  6. data/lib/rails_wizard/recipes.rb +38 -0
  7. data/lib/rails_wizard/template.rb +58 -0
  8. data/lib/rails_wizard.rb +10 -0
  9. data/recipes/action_mailer.rb +41 -0
  10. data/recipes/activerecord.rb +37 -0
  11. data/recipes/add_user_name.rb +75 -0
  12. data/recipes/application_layout.rb +43 -0
  13. data/recipes/ban_spiders.rb +19 -0
  14. data/recipes/capybara.rb +34 -0
  15. data/recipes/cleanup.rb +34 -0
  16. data/recipes/css_setup.rb +40 -0
  17. data/recipes/cucumber.rb +69 -0
  18. data/recipes/devise.rb +35 -0
  19. data/recipes/devise_navigation.rb +95 -0
  20. data/recipes/env_yaml.rb +54 -0
  21. data/recipes/git.rb +26 -0
  22. data/recipes/haml.rb +14 -0
  23. data/recipes/heroku.rb +58 -0
  24. data/recipes/home_page.rb +43 -0
  25. data/recipes/home_page_users.rb +50 -0
  26. data/recipes/hoptoad.rb +34 -0
  27. data/recipes/jammit.rb +43 -0
  28. data/recipes/jquery.rb +44 -0
  29. data/recipes/less.rb +12 -0
  30. data/recipes/mongo_mapper.rb +18 -0
  31. data/recipes/mongohq.rb +59 -0
  32. data/recipes/mongoid.rb +30 -0
  33. data/recipes/mootools.rb +23 -0
  34. data/recipes/omniauth.rb +15 -0
  35. data/recipes/pow.rb +12 -0
  36. data/recipes/prototype.rb +11 -0
  37. data/recipes/rails_admin.rb +21 -0
  38. data/recipes/redis.rb +17 -0
  39. data/recipes/redistogo.rb +40 -0
  40. data/recipes/rightjs.rb +17 -0
  41. data/recipes/rspec.rb +89 -0
  42. data/recipes/sass.rb +13 -0
  43. data/recipes/seed_database.rb +35 -0
  44. data/recipes/sequel.rb +13 -0
  45. data/recipes/settingslogic.rb +43 -0
  46. data/recipes/slim.rb +11 -0
  47. data/recipes/test_unit.rb +11 -0
  48. data/recipes/users_page.rb +103 -0
  49. data/spec/rails_wizard/config_spec.rb +99 -0
  50. data/spec/rails_wizard/recipe_spec.rb +103 -0
  51. data/spec/rails_wizard/recipes/sanity_spec.rb +30 -0
  52. data/spec/rails_wizard/recipes_spec.rb +24 -0
  53. data/spec/rails_wizard/template_spec.rb +48 -0
  54. data/spec/spec_helper.rb +11 -0
  55. data/spec/support/rails_directory.rb +17 -0
  56. data/spec/support/template_runner.rb +28 -0
  57. data/templates/helpers.erb +45 -0
  58. data/templates/layout.erb +46 -0
  59. data/templates/recipe.erb +10 -0
  60. data/version.rb +3 -0
  61. 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 &quot;supergem:install&quot;
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,7 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'rubygems'
5
+ require 'rails_wizard/command'
6
+
7
+ RailsWizard::Command.start
@@ -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