suspenders 0.0.4 → 0.1.0.beta.1

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/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'cucumber/rake/task'
4
4
  require 'date'
5
5
 
6
6
  TEST_PROJECT = 'test_project'
7
- SUSPENDERS_GEM_VERSION = '0.0.4'
7
+ SUSPENDERS_GEM_VERSION = '0.1.0.beta.1'
8
8
 
9
9
  #############################################################################
10
10
  #
@@ -16,34 +16,18 @@ Cucumber::Rake::Task.new
16
16
 
17
17
  namespace :test do
18
18
  desc "A full suspenders app's test suite"
19
- task :full => ['generate', 'cucumber', 'destroy:suspenders']
19
+ task :full => ['test_project:generate', 'cucumber', 'test_project:destroy']
20
20
  end
21
21
 
22
- task :generate => ['generate:finish']
23
- namespace :generate do
22
+ namespace :test_project do
24
23
  desc 'Suspend a new project. Pass REPO=... to change the Suspenders repo.'
25
- task :suspenders do
24
+ task :generate do
26
25
  FileUtils.rm_rf(TEST_PROJECT)
27
26
  sh './bin/suspenders', 'create', TEST_PROJECT, ENV['REPO'].to_s
28
27
  end
29
28
 
30
- desc 'Finishing touches'
31
- task :finish => ['suspenders'] do
32
- open(File.join(TEST_PROJECT, 'config', 'environments', 'cucumber.rb'), 'a') do |f|
33
- f.puts "config.action_mailer.default_url_options = { :host => 'localhost:3000' }"
34
- end
35
-
36
- routes_file = IO.read(File.join(TEST_PROJECT, 'config', 'routes.rb')).split("\n")
37
- routes_file = [routes_file[0]] + [%{map.root :controller => 'clearance/sessions', :action => 'new'}] + routes_file[1..-1]
38
- open(File.join(TEST_PROJECT, 'config', 'routes.rb'), 'w') do |f|
39
- f.puts routes_file.join("\n")
40
- end
41
- end
42
- end
43
-
44
- namespace :destroy do
45
29
  desc 'Remove a suspended project'
46
- task :suspenders do
30
+ task :destroy do
47
31
  FileUtils.cd TEST_PROJECT
48
32
  sh "rake db:drop RAILS_ENV=development"
49
33
  sh "rake db:drop RAILS_ENV=test"
@@ -12,7 +12,7 @@ end
12
12
  case ARGV[0]
13
13
  when 'create', '--create'
14
14
  begin
15
- Suspenders::Create.run!(ARGV[1], ARGV[2])
15
+ Suspenders::Create.run!(ARGV[1])
16
16
  rescue Suspenders::InvalidInput => e
17
17
  error_with_message(e.message)
18
18
  end
@@ -9,7 +9,7 @@ Feature: Rake works in the suspended project
9
9
 
10
10
  Scenario: Making a spec then running rake
11
11
  When I drop and create the required databases
12
- And I generate "rspec_model post title:string"
12
+ And I generate "model post title:string"
13
13
  And I run the rake task "db:migrate"
14
14
  And I run the rake task "spec"
15
15
  Then I see a successful response in the shell
@@ -6,7 +6,7 @@ end
6
6
 
7
7
  When 'I generate "$generator_with_args"' do |generator_with_args|
8
8
  Dir.chdir('test_project') do
9
- system("./script/generate #{generator_with_args}")
9
+ system("rails generate #{generator_with_args}")
10
10
  end
11
11
  end
12
12
 
@@ -1,106 +1,54 @@
1
1
  # Methods needed to create a project.
2
2
 
3
3
  require 'rubygems'
4
- require 'digest/md5'
5
4
  require File.expand_path(File.dirname(__FILE__) + "/errors")
6
- require File.expand_path(File.dirname(__FILE__) + "/command")
7
5
 
8
6
  module Suspenders
9
7
  class Create
10
- attr_accessor :project_name, :template_url, :project_directory
11
- include Suspenders::Command
8
+ attr_accessor :project_path
12
9
 
13
- def self.run!(input_project_name, input_template_url)
14
- creator = self.new(input_project_name, input_template_url)
10
+ def self.run!(project_path)
11
+ creator = self.new(project_path)
15
12
  creator.create_project!
16
13
  end
17
14
 
18
- def initialize(input_project_name, input_template_url)
19
- @project_name = valid_project_name!(input_project_name)
20
- @template_url, @project_directory = valid_template_url!(input_template_url, project_name)
15
+ def initialize(project_path)
16
+ self.project_path = project_path
17
+ validate_project_path
18
+ validate_project_name
21
19
  end
22
20
 
23
21
  def create_project!
24
- run("mkdir #{project_directory}")
25
- Dir.chdir(project_directory) or fail("Couldn't change to #{project_directory}")
26
- run("git init")
27
- run("git remote add suspenders #{template_url}")
28
- run("git pull suspenders master")
29
-
30
- Dir.glob("#{project_directory}/**/*.*").each do |file|
31
- search_and_replace(file, changeme, project_name)
32
- end
33
-
34
- Dir.glob("#{project_directory}/**/session_store.rb").each do |file|
35
- datestring = Time.now.strftime("%j %U %w %A %B %d %Y %I %M %S %p %Z")
36
- search_and_replace(file, changesession, Digest::MD5.hexdigest("#{project_name} #{datestring}"))
37
- end
38
-
39
- run("git commit -a -m 'Initial commit'")
40
-
41
- run("rake gems:refresh_specs")
42
- run("rake db:create RAILS_ENV=development")
43
- run("rake db:create RAILS_ENV=test")
44
-
45
- run("script/generate clearance")
46
- run("script/generate clearance_features -f")
47
- run("script/generate clearance_views -f")
48
-
49
- run("git add .")
50
- run("git commit -m 'installed clearance'")
51
-
52
- puts
53
- puts "Now login to github and add a new project named '#{project_name}'"
22
+ exec(<<-COMMAND)
23
+ rails new #{project_path} \
24
+ --template=#{template} \
25
+ --skip-test-unit \
26
+ --skip-prototype
27
+ COMMAND
54
28
  end
55
29
 
56
30
  private
57
31
 
58
- def changeme
59
- "CHANGEME"
60
- end
61
-
62
- def changesession
63
- "CHANGESESSION"
64
- end
65
-
66
- def valid_project_name!(project_name)
32
+ def validate_project_name
33
+ project_name = File.basename(project_path)
67
34
  unless project_name =~ /^[a-z0-9_]+$/
68
35
  raise InvalidInput.new("Project name must only contain [a-z0-9_]")
69
- else
70
- project_name
71
36
  end
72
37
  end
73
38
 
74
- def valid_template_url!(template_url, project_name)
39
+ def validate_project_path
75
40
  base_directory = Dir.pwd
76
- project_directory = File.join(base_directory, project_name)
41
+ full_path = File.join(base_directory, project_path)
77
42
 
78
43
  # This is for the common case for the user's convenience; the race
79
44
  # condition can still occur.
80
- if File.exists?(project_directory)
81
- raise InvalidInput.new("Project directory (#{project_directory}) already exists")
82
- end
83
-
84
- if template_url && !(template_url =~ /^ *$/)
85
- [template_url, project_directory]
86
- else
87
- ["git://github.com/thoughtbot/suspenders.git", project_directory]
45
+ if File.exists?(full_path)
46
+ raise InvalidInput.new("Project directory (#{project_path}) already exists")
88
47
  end
89
48
  end
90
49
 
91
- def search_and_replace(file, search, replace)
92
- begin
93
- contents = File.read(file)
94
- if contents[search]
95
- puts "Replacing #{search} with #{replace} in #{file}"
96
- contents.gsub!(search, replace)
97
- File.open(file, "w") { |f| f << contents }
98
- end
99
- rescue Errno::EISDIR => e
100
- # This is fine, because Dir.glob can't select only files.
101
- rescue Errno::ENOENT => e
102
- fail "Attempted to perform a find-and-replace on a missing file: #{file}"
103
- end
50
+ def template
51
+ File.expand_path(File.dirname(__FILE__) + "/../template/suspenders.rb")
104
52
  end
105
53
  end
106
54
  end
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
4
4
  s.rubygems_version = '1.3.5'
5
5
 
6
6
  s.name = 'suspenders'
7
- s.version = '0.0.4'
8
- s.date = '2010-08-10'
7
+ s.version = '0.1.0.beta.1'
8
+ s.date = '2010-09-28'
9
9
 
10
10
  s.summary = "Generate a Rails app using thoughtbot's best practices."
11
11
  s.description = <<-HERE
@@ -24,15 +24,8 @@ rush to build something amazing; don't use it if you like missing deadlines.
24
24
  s.rdoc_options = ["--charset=UTF-8"]
25
25
  s.extra_rdoc_files = %w[README.md LICENSE]
26
26
 
27
- s.add_dependency('cucumber', [">= 0.6.2"])
28
- s.add_dependency('nokogiri', '1.4.0')
29
- s.add_dependency('RedCloth', '4.2.2')
30
- s.add_dependency('cucumber-rails', '>=0.3.0')
31
- s.add_dependency('mysql', '2.8.1')
32
- s.add_dependency('rspec','1.3.0')
33
- s.add_dependency('rspec-rails','= 1.3.2')
34
- s.add_dependency('webrat','>=0.7.0')
35
- s.add_dependency('treetop','1.4.5')
27
+ s.add_dependency('rails', '>= 3.0.0')
28
+ s.add_dependency('trout', '>= 0.3.0')
36
29
 
37
30
  # = MANIFEST =
38
31
  s.files = %w[
@@ -43,10 +36,24 @@ rush to build something amazing; don't use it if you like missing deadlines.
43
36
  features/rake_clean.feature
44
37
  features/step_definitions/shell.rb
45
38
  features/support/env.rb
46
- lib/command.rb
47
39
  lib/create.rb
48
40
  lib/errors.rb
49
41
  suspenders.gemspec
42
+ template/files/README_FOR_SUSPENDERS
43
+ template/files/_flashes.html.erb
44
+ template/files/_javascript.html.erb
45
+ template/files/body_class_helper.rb
46
+ template/files/errors.rb
47
+ template/files/factory_girl_steps.rb
48
+ template/files/mysql_database.yml.erb
49
+ template/files/suspenders_gitignore
50
+ template/files/suspenders_layout.html.erb.erb
51
+ template/files/time_formats.rb
52
+ template/suspenders.rb
53
+ template/trout/Gemfile
54
+ template/trout/public/javascripts/jquery-ui.js
55
+ template/trout/public/javascripts/jquery.js
56
+ template/trout/public/javascripts/prefilled_input.js
50
57
  ]
51
58
  # = MANIFEST =
52
59
 
@@ -0,0 +1,166 @@
1
+ This is Suspenders, the thoughtbot rails template.
2
+
3
+ To create a new project, first install the suspenders gem:
4
+
5
+ gem install suspenders
6
+
7
+ Then run:
8
+
9
+ suspenders create projectname
10
+
11
+ This will create a project in ../projectname. You should then follow the
12
+ instructions on Github to upload that project there. This creates an
13
+ entirely new git repository, and is not meant to be used against an existing
14
+ repo.
15
+
16
+ When making a change to a project that was created via this template, consider
17
+ whether it's a change that should be made across all projects. If so, then
18
+ make the change in suspenders instead of your project. Note: If you don't
19
+ have commit access to suspenders, create a github ticket and we'll review your
20
+ suggestion.
21
+
22
+ Once that's committed, you can pull into your project to get all the changes
23
+ that have been made in suspenders since your last pull:
24
+
25
+ rake git:pull:suspenders
26
+
27
+ About Suspenders
28
+ ----------------
29
+
30
+ Suspenders was created for use at thoughtbot, inc. (http://thoughtbot.com) as a
31
+ baseline application setup, with reasonable default plugins that the majority
32
+ (if not all) of our applications used, as well as best-practice configuration
33
+ options.
34
+
35
+ Suspenders currently includes a version of Rails from the 2.3 stable branch.
36
+ You can determine the changeset with the vendor/rails/REVISION_xxxxx file.
37
+
38
+ Gems (unpacked in vendor/gems, unless they are compiled gems):
39
+ --------------------------------------------------------------
40
+
41
+ For record pagination:
42
+
43
+ will_paginate
44
+
45
+ For text formatting:
46
+
47
+ RedCloth (4.2.2, not unpacked, this is a compiled gem)
48
+
49
+ Form builder:
50
+
51
+ Formtastic
52
+
53
+ File attachments:
54
+
55
+ Paperclip
56
+
57
+ Basic user auth:
58
+
59
+ Clearance
60
+
61
+ For testing:
62
+
63
+ jferris-mocha (standard mocha plus test spies)
64
+ factory_girl (fixture replacement for test data)
65
+ shoulda (rails test helpers and context framework)
66
+ timecop (for time sensitive tests)
67
+ fakeweb (for blocking HTTP calls to third-party services)
68
+
69
+ Error notification:
70
+
71
+ hoptoad_notifier
72
+
73
+ Plugins (in vendor/plugins):
74
+ ----------------------------
75
+
76
+ limerick_rake (useful rake tasks)
77
+ validation_reflection (used by formtastic to find required fields)
78
+ high_voltage (Rails engine for static pages)
79
+
80
+ Initializers (in config/initializers)
81
+ -------------------------------------
82
+
83
+ action_mailer_configs.rb
84
+ We use SMTP by default in all applications.
85
+
86
+ hoptoad.rb
87
+ Get your API key at http://hoptoadapp.com
88
+
89
+ requires.rb
90
+ Automatically requires everything in
91
+ lib/
92
+ lib/extensions
93
+ test/mocks/RAILS_ENV (Removed in Rails 2, we decided to keep it)
94
+ Add other things you need to require in here.
95
+
96
+ time_formats.rb
97
+ Two time formats are available by default, :short_date and :long_date.
98
+ Add other time formats here.
99
+
100
+ Rake Tasks
101
+ ----------
102
+
103
+ Rake tasks are contained in the limerick_rake gem.
104
+
105
+ bootstrap
106
+ Provides rake tasks for loading data into the database. These are used for
107
+ an initial application dataset needed for production.
108
+
109
+ capistrano
110
+ Standard capistrano deployment tasks
111
+
112
+ Testing
113
+ -------
114
+
115
+ Testing is done utilizing Test::Unit, Shoulda, factory_girl, and mocha.
116
+
117
+ factory_girl is a fixture replacement library, following the factory pattern.
118
+ Place your factories in test/factories.rb. The fixture directory has been
119
+ removed, as fixtures are not used.
120
+
121
+ Shoulda is a pragmatic testing framework for TDD and BDD built on top of
122
+ Test::Unit. A number of additional testing macros are provided in
123
+ test/shoulda_macros:
124
+
125
+ shoulda_have_form
126
+ shoulda_paginate_collection
127
+
128
+ Timecop is used to freeze the time for the entire test suite. It is frozen to
129
+ the value of Time.now; that is, the time that the tests suite starts running.
130
+
131
+ Deployment
132
+ ----------
133
+
134
+ Deployment is done using capistrano, and deploys to a mongrel cluster, running
135
+ under Apache.
136
+
137
+ Rake tasks are provided for managing git branches which the different
138
+ environments pull from for deploy.
139
+
140
+ To push the git master to git staging branch run:
141
+
142
+ rake git:push:staging
143
+
144
+ To push the git staging branch to production branch run:
145
+
146
+ rake git:push:production
147
+
148
+ Setup your deployment environment by running:
149
+
150
+ cap ENVIRONMENT deploy:setup
151
+ (You'll be prompted for the environment's database password)
152
+
153
+ Deploy to the desired environment by running:
154
+
155
+ cap ENVIRONMENT deploy
156
+
157
+ The default environment for deploy is staging, to deploy to staging, just run:
158
+
159
+ cap deploy
160
+
161
+ Mascot
162
+ ------
163
+
164
+ The official Suspenders mascot is Suspenders Boy:
165
+
166
+ http://media.tumblr.com/1TEAMALpseh5xzf0Jt6bcwSMo1_400.png
@@ -0,0 +1,5 @@
1
+ <div id="flash">
2
+ <% flash.each do |key, value| -%>
3
+ <div id="flash_<%= key %>"><%=h value %></div>
4
+ <% end -%>
5
+ </div>
@@ -0,0 +1,2 @@
1
+ <%= javascript_include_tag 'jquery', 'jquery-ui', 'prefilled_input', :cache => true %>
2
+ <%= yield :javascript %>
@@ -0,0 +1,7 @@
1
+ module BodyClassHelper
2
+ # TODO: move this into a gem/plugin
3
+ def body_class
4
+ qualified_controller_name = controller.controller_path.gsub('/','-')
5
+ "#{qualified_controller_name} #{qualified_controller_name}-#{controller.action_name}"
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ require 'net/smtp'
2
+ # Example:
3
+ # begin
4
+ # some http call
5
+ # rescue *HTTP_ERRORS => error
6
+ # notify_hoptoad error
7
+ # end
8
+
9
+ HTTP_ERRORS = [Timeout::Error,
10
+ Errno::EINVAL,
11
+ Errno::ECONNRESET,
12
+ EOFError,
13
+ Net::HTTPBadResponse,
14
+ Net::HTTPHeaderSyntaxError,
15
+ Net::ProtocolError]
16
+
17
+ SMTP_SERVER_ERRORS = [TimeoutError,
18
+ IOError,
19
+ Net::SMTPUnknownError,
20
+ Net::SMTPServerBusy,
21
+ Net::SMTPAuthenticationError]
22
+
23
+ SMTP_CLIENT_ERRORS = [Net::SMTPFatalError,
24
+ Net::SMTPSyntaxError]
25
+
26
+ SMTP_ERRORS = SMTP_SERVER_ERRORS + SMTP_CLIENT_ERRORS