suspenders 0.0.4 → 0.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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