Skip to content

Instantly share code, notes, and snippets.

@jeriko
Created February 19, 2012 21:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jeriko/1865932 to your computer and use it in GitHub Desktop.
Save jeriko/1865932 to your computer and use it in GitHub Desktop.
KICKSTART v1
class AppBuilder < Rails::AppBuilder
include Thor::Actions
include Thor::Shell
# Express app templating for Rails
# ------------------------------------
# USAGE:
# 1. Add gems to `gem_dependencies`
# 2. Methods listed in SCRIPTS will be run after bundling, so make sure they each have a declaration
# 3. run: `rails new app_name --builder=path/to/builder.rb` (URI's work here too)
# 4. ???
# 5. PROFIT!
# This method will be run as soon as the builder takes control
def init
say 'Code monkey ready to work!', :green
@use_thin = yes?('Use thin-rails as the default server?')
@use_slim = yes?('Swap out ERB with SLIM?')
@use_bootstrap = yes?('Install twitter_bootstrap?')
if @use_bootstrap
@use_bootstrap_responsive = yes?('Install responsive twitter_bootstrap?')
end
@use_chosen = yes?('Install jQuery-chosen?')
@use_ranked_model = yes?('Install ranked-model?')
end
# Add your gem dependencies here
def gem_dependencies
# thin
@generator.gem 'thin-rails' if @use_thin
# slim
@generator.gem 'slim-rails' if @use_slim
# inherited_resources
@generator.gem 'inherited_resources'
# simple_form
@generator.gem 'simple_form', git: 'git://github.com/plataformatec/simple_form.git'
@generator.gem 'country_select'
# compass-sass + bootstrap
@generator.gem_group :assets do
gem 'therubyracer'
gem 'compass-rails'
gem 'compass_twitter_bootstrap'
end
# ranked model
@generator.gem 'ranked-model' if @use_ranked_model
# test framework
@generator.gem_group :test, :development do
gem 'rspec-rails'
gem 'factory_girl_rails'
# TODO the rest
end
# chosen
@generator.gem 'chosen-rails' if @use_chosen
end
# Add any script declarations here, and make sure you build their corresponding methods
SCRIPTS = [
:spec, :sass, :coffeescript,
:bootstrap, :chosen, :css_utils, # asset plugins
:simple_form, :app_index_slim, # views
:rvm_gemset, # rvm
:file_cleanup, # general
:git_init # git
]
def spec
generate 'rspec:install'
end
def sass
# sets up app/assets/stylesheets/application.css.sass as required, with hooks for `manifest` and `import`s
css_asset_path = File.join %w(app assets stylesheets application.css)
@generator.remove_file(css_asset_path)
@sass_asset_path = File.join %w(app assets stylesheets application.css.sass)
@generator.create_file @sass_asset_path, <<-SASS
// MANIFEST: start
// MANIFEST: end
// IMPORTS: start
// IMPORTS: end
SASS
sass_add_manifest 'require_self'
sass_add_import 'compass'
end
def coffeescript
# sets up app/assets/javascripts/application.js.coffee as required, with hooks for `manifest` and `jquery onready`
js_asset_path = File.join %w(app assets javascripts application.js)
@generator.remove_file(js_asset_path)
@coffee_asset_path = File.join %w(app assets javascripts application.js.coffee)
@generator.create_file @coffee_asset_path, <<-COFFEE
// MANIFEST: start
// MANIFEST: end
$(document).ready ->
# ONREADY: start
# ONREADY: end
COFFEE
coffee_add_manifest require: 'jquery'
coffee_add_manifest require: 'jquery_ujs'
coffee_add_manifest require: 'jquery-ui'
coffee_add_manifest 'require_tree .'
end
def bootstrap
return unless @use_bootstrap
sass_add_import 'compass_twitter_bootstrap'
sass_add_import 'compass_twitter_bootstrap_responsive'
# TODO bootstrap js imports...
end
def chosen
return unless @use_chosen
sass_add_manifest require: 'chosen'
coffee_add_manifest require: 'chosen-jquery'
coffee_add_ready "$('.chzn-select').chosen();"
end
def css_utils
# TODO sticky_footer etc.
end
def simple_form
generate "simple_form:install #{'--bootstrap' if @use_bootstrap}"
end
def app_index_slim
return unless @use_slim
# sets up app/views/layouts/index.html.slim as required
erb_index_path = File.join %w(app views layouts application.html.erb)
@generator.remove_file(erb_index_path)
slim_index_path = File.join %w(app views layouts application.html.slim)
@generator.create_file slim_index_path,
<<-SLIM
doctype 5
html
head
title #{app_name}
= stylesheet_link_tag 'application', :media => 'all'
= javascript_include_tag 'application'
= csrf_meta_tags
body class='\#{controller_name}'
= yield
SLIM
end
# TODO nifty generators
# TODO nifty config
# TODO carrierwave
# TODO airbrake
# TODO rails-best-practices (and the other outputter gem for development)
# TODO newrelic etc.
# TODO jquery shims
def rvm_gemset
# TODO
end
def file_cleanup
@generator.remove_file File.join %w(public index.html)
@generator.remove_file File.join %w(app assets images rails.png)
@generator.remove_file File.join %w(README.rdoc)
# remove the finder-tags in application.js.coffee
@generator.gsub_file(@coffee_asset_path, '// MANIFEST: start', '')
@generator.gsub_file(@coffee_asset_path, '// MANIFEST: end', '')
@generator.gsub_file(@coffee_asset_path, ' # ONREADY: start', '')
@generator.gsub_file(@coffee_asset_path, ' # ONREADY: end', '')
# remove the finder-tags in application.css.sass
@generator.gsub_file(@sass_asset_path, '// MANIFEST: start', '')
@generator.gsub_file(@sass_asset_path, '// MANIFEST: end', '')
@generator.gsub_file(@sass_asset_path, '// IMPORTS: start', '')
@generator.gsub_file(@sass_asset_path, '// IMPORTS: end', '')
end
def git_init
git :init
git add: '.'
git commit: "-m \"AppBuilder: #{app_name}\""
end
# ---------------------------------------------------
# - v You can safely ignore below this line v -
# ---------------------------------------------------
def gemfile
# `gemfile` is the first method called on Rails::AppBuilder, so let's hook into the process for config
init
# invoke default behaviour via `super`
# alternatively, use `template 'Gemfile'`, but let's not step on toes
super
# add dependencies to Gemfile
say 'Adding gem dependencies to Gemfile', :yellow
gem_dependencies
# we need dependencies installed right away, so their generators can be run BEFORE
# the scheduled run of bundler (at end of app generation)
# This dirty hack will have to do until I can figure out how to hook in commands AFTER bundler actually runs
say 'Running bundler', :yellow
run_bundle
# stop bundler running in future:
@generator.options = @generator.options.dup
@generator.options[:skip_bundle] = true
@generator.options.freeze
end
def test
return
# TODO
# skips test framework, but we can probably just bastardize the options in the same way as with :skip_bundle
# either make `test` build the actual directories etc., or use a script
# either way, this method is stupid.
end
def leftovers
SCRIPTS.each { |g|
say "Script: #{g}", :red
send(g)
}
say "Finished generating #{app_name}!", :green
say 'Saving Daniel time testing...', :blue
generate "scaffold person name dob:date rank:integer"
# ranking
@generator.inject_into_file 'app/models/person.rb', before: 'end' do
" include RankedModel\n ranks :rank\n default_scope rank(:rank)\n"
end
@generator.remove_file 'app/views/people/index.html.slim'
@generator.create_file 'app/views/people/index.html.slim', <<-SORTABLES
h1 Listing people
ul#people
- @people.each do |person|
li data-id=person.id data-name=person.name style='width:300px;'
span.handle.close &times;
h2 = person.name
span.label.label-success = person.id
span.label = person.rank
em = person.dob || 'No D.O.B'
.btn-group
= link_to 'Show', person, class: 'btn'
= link_to 'Edit', edit_person_path(person), class: 'btn'
= link_to 'Destroy', person, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger'
br
= link_to 'New Person', new_person_path
javascript:
$(function() {
$('#people').sortable({
handle: '.handle',
update: function(event,ui) {
var item = ui.item;
var item_id = item.attr('data-id');
var item_index = item.parent().children().index(item);
var request_params = { person: { id: item_id, rank_position: item_index } };
$.ajax({
type: 'put',
url: '/people/' + item_id,
data: request_params,
success: function(r) { console.log('success'); },
error: function() { console.log('error. TODO element should be returned to original position.'); }
});
}
});
});
SORTABLES
# add the jquery behaviour...
rake "db:migrate"
say "She's all yours, sparky!\n\n", :green
end
# ASSET PIPELINE HELPERS:
def add_manifest(path, directive)
r = directive.is_a?(String) ? directive : "require #{directive.delete(:require)}"
@generator.inject_into_file path, before: '// MANIFEST: end' do
"//= #{r}\n"
end
end
def sass_add_manifest(directive)
add_manifest(@sass_asset_path, directive)
end
def coffee_add_manifest(directive)
add_manifest(@coffee_asset_path, directive)
end
def sass_add_import(i)
@generator.inject_into_file @sass_asset_path, before: '// IMPORTS: end' do
"@import '#{i}'\n"
end
end
def coffee_add_ready(js)
@generator.inject_into_file @coffee_asset_path, before: ' # ONREADY: end' do
" #{js}\n"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment