├── spec ├── support │ └── .gitkeep ├── recipes │ └── home_controller_recipe_spec.rb ├── spec_helper.rb └── cookbook_spec.rb ├── test └── dummy │ └── log │ └── development.log ├── .rspec ├── recipes ├── templates │ ├── rspec_recipe │ │ └── .gitkeep │ ├── capistrano_recipe │ │ ├── .gitkeep │ │ └── deploy.rb │ ├── assets_recipe │ │ ├── stylesheets │ │ │ ├── media.css.scss │ │ │ ├── partials │ │ │ │ ├── _simple_form.css.scss │ │ │ │ ├── _html5-boilerplate.css.scss │ │ │ │ ├── _constants.css.scss │ │ │ │ ├── _buttons.css.scss │ │ │ │ ├── html5-boilerplate │ │ │ │ │ ├── _reset.css.scss │ │ │ │ │ ├── _fonts.css.scss │ │ │ │ │ ├── _helpers.css.scss │ │ │ │ │ ├── _media.css.scss │ │ │ │ │ └── _styles.css.scss │ │ │ │ ├── _forms.css.scss │ │ │ │ ├── _shared.css.scss │ │ │ │ ├── _overrides.css.scss │ │ │ │ └── _layout.css.scss │ │ │ └── application.css.scss │ │ └── images │ │ │ ├── bg.jpg │ │ │ └── input-bg.gif │ ├── home_controller_recipe │ │ └── _sidebar.html.erb │ ├── application_controller_recipe │ │ ├── internal_error.html.erb │ │ ├── not_found.html.erb │ │ └── application_controller.rb │ ├── cancan_recipe │ │ ├── role.rb │ │ ├── user_role.rb │ │ └── ability.rb │ ├── application_helper_recipe │ │ ├── flash_messages_mootools.js.coffee │ │ ├── flash_messages_jquery.js.coffee │ │ └── playmo_helper.rb │ ├── thinking_sphinx_recipe │ │ └── sphinx.yml │ └── unicorn_recipe │ │ └── unicorn.rb ├── rails_recipe.rb ├── gemfile_recipe.rb ├── compass_recipe.rb ├── assets_recipe.rb ├── unicorn_recipe.rb ├── database_recipe.rb ├── layout_recipe.rb ├── capistrano_recipe.rb ├── rvm_recipe.rb ├── thinking_sphinx_recipe.rb ├── forms_recipe.rb ├── markup_recipe.rb ├── rspec_recipe.rb ├── application_controller_recipe.rb ├── git_recipe.rb ├── setup_database_recipe.rb ├── application_helper_recipe.rb ├── locale_recipe.rb ├── javascript_framework_recipe.rb ├── home_controller_recipe.rb ├── cancan_recipe.rb └── devise_recipe.rb ├── .gitignore ├── Rakefile ├── Gemfile ├── lib ├── playmo │ ├── event.rb │ ├── version.rb │ ├── silent.rb │ ├── recipe.rb │ ├── options.rb │ ├── answer.rb │ ├── action.rb │ ├── choice.rb │ ├── recipe │ │ ├── dsl.rb │ │ └── recipe.rb │ ├── cli.rb │ ├── cookbook.rb │ └── question.rb ├── generators │ ├── templates │ │ ├── erb │ │ │ └── scaffold │ │ │ │ ├── new.html.erb │ │ │ │ ├── edit.html.erb │ │ │ │ ├── index.html.erb │ │ │ │ └── show.html.erb │ │ ├── active_record │ │ │ └── model │ │ │ │ └── model.rb │ │ └── rails │ │ │ └── scaffold_controller │ │ │ └── controller.rb │ └── rails │ │ ├── layout_generator.rb │ │ └── templates │ │ ├── layout.html.slim │ │ ├── layout.html.haml │ │ └── layout.html.erb └── playmo.rb ├── bin └── playmo ├── playmo.gemspec ├── TODO.md └── README.md /spec/support/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/dummy/log/development.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format=progress -------------------------------------------------------------------------------- /recipes/templates/rspec_recipe/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/templates/capistrano_recipe/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/stylesheets/media.css.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject/ 2 | .rvmrc 3 | .idea/ 4 | Gemfile.lock 5 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in playmo.gemspec 4 | gemspec -------------------------------------------------------------------------------- /lib/playmo/event.rb: -------------------------------------------------------------------------------- 1 | require 'ruby_events' 2 | 3 | module Playmo 4 | module Event 5 | 6 | end 7 | end -------------------------------------------------------------------------------- /bin/playmo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | $:.unshift File.expand_path("../../lib", __FILE__) 3 | 4 | require 'playmo' 5 | 6 | Playmo::Cli.start(ARGV) -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanraya/playmo/HEAD/recipes/templates/assets_recipe/images/bg.jpg -------------------------------------------------------------------------------- /lib/generators/templates/erb/scaffold/new.html.erb: -------------------------------------------------------------------------------- 1 | <%%= heading_with_title "New <%= singular_table_name.camelize %>" %> 2 | 3 | <%%= render 'form' %> -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/images/input-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tanraya/playmo/HEAD/recipes/templates/assets_recipe/images/input-bg.gif -------------------------------------------------------------------------------- /lib/playmo/version.rb: -------------------------------------------------------------------------------- 1 | module Playmo 2 | VERSION = "0.1.10" 3 | 4 | if ARGV.first =~ /--version|-v/ 5 | puts VERSION 6 | exit! 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /recipes/templates/home_controller_recipe/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
Content for sidebar.
3 |This content displayed at inner pages.
4 | -------------------------------------------------------------------------------- /lib/playmo/silent.rb: -------------------------------------------------------------------------------- 1 | module Playmo 2 | class Silent 3 | def initialize(recipe, &block) 4 | Playmo::Action.new(recipe, &block) 5 | end 6 | end 7 | end -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/stylesheets/partials/_simple_form.css.scss: -------------------------------------------------------------------------------- 1 | .field_with_errors { 2 | span.error { 3 | color: red; 4 | padding: 0 0 0 7px; 5 | display: block; 6 | } 7 | } -------------------------------------------------------------------------------- /recipes/templates/application_controller_recipe/internal_error.html.erb: -------------------------------------------------------------------------------- 1 | <%= heading_with_title "500 Error. It seems that something went wrong :(" %> 2 | 3 |4 | We have already notified of the error. Please, visit us later. 5 |
6 | -------------------------------------------------------------------------------- /recipes/rails_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :rails do 2 | description 'This will create new Rails application' 3 | after :database 4 | 5 | silently do 6 | system "rails new #{application_name} -JT --skip-bundle -d #{retrieve(:database)}" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /recipes/templates/application_controller_recipe/not_found.html.erb: -------------------------------------------------------------------------------- 1 | <%= heading_with_title "404 Error. Looks like you either get there." %> 2 | 3 |4 | This is a 404 error, it either means that this page was removed or it never existed (it happens). 5 |
6 | -------------------------------------------------------------------------------- /recipes/gemfile_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :gemfile do 2 | description 'This will add necessary gems' 3 | after :rvm 4 | 5 | silently do 6 | gem 'rake', '~> 0.9.2' 7 | gem 'therubyracer', '0.9.9' 8 | gem 'playmo', Playmo::VERSION, :group => :development 9 | end 10 | end -------------------------------------------------------------------------------- /recipes/templates/cancan_recipe/role.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class Role < ActiveRecord::Base 4 | has_many :users, :through => :user_role 5 | 6 | attr_accessible :name, :description 7 | validates :name, :description, :presence => true 8 | 9 | def to_s 10 | name 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/generators/templates/active_record/model/model.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | <% module_namespacing do -%> 4 | class <%= class_name %> < <%= parent_class_name.classify %> 5 | <%- attributes.select {|attr| attr.reference? }.each do |attribute| -%> 6 | belongs_to :<%= attribute.name %> 7 | <% end -%> 8 | end 9 | <% end -%> 10 | -------------------------------------------------------------------------------- /recipes/compass_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :compass do 2 | description 'This will add Stylesheet Authoring Environment that makes your website design simpler to implement and easier to maintain' 3 | after :application_controller 4 | 5 | ask "Would you like to use Compass in this project?" do 6 | gem "compass", "0.12.alpha.4" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/generators/templates/erb/scaffold/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%%= heading_with_title "Editing <%= singular_table_name.camelize %>" %> 2 | 3 | <%%= render 'form' %> 4 | 5 | <%%= private_area true do %> 6 | <%%= link_to "Destroy <%= singular_table_name.camelize %>?", @<%= singular_table_name %>, confirm: 'Are you sure?', method: :delete %> 7 | <%% end %> 8 | 9 | -------------------------------------------------------------------------------- /recipes/assets_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :assets do 2 | description 'This will adds custom assets into application' 3 | after :markup 4 | 5 | silently do 6 | directory 'images/', 'app/assets/images/' 7 | directory 'stylesheets/', 'app/assets/stylesheets/' 8 | remove_file 'app/assets/stylesheets/application.css' 9 | end 10 | end -------------------------------------------------------------------------------- /recipes/unicorn_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :unicorn do 2 | description 'This will add Unicorn - Rack HTTP server for fast clients and Unix' 3 | after :application_helper 4 | 5 | ask "Would you like to use Unicorn as web server in production?" do 6 | gem "unicorn", :group => :production 7 | template "unicorn.rb", "config/unicorn.rb" 8 | end 9 | end -------------------------------------------------------------------------------- /recipes/database_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :database do 2 | description 'This will setup database for your app' 3 | after nil 4 | 5 | question "Which database you prefer to use?" do 6 | answer "MySQL", :default => true do 7 | store :database, :mysql 8 | end 9 | 10 | answer "SQLite" do 11 | store :database, :sqlite3 12 | end 13 | end 14 | end -------------------------------------------------------------------------------- /recipes/layout_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :layout do 2 | description 'This will generate HTML5-ready layout for your app' 3 | after :javascript_framework 4 | 5 | # TODO: Add option to make separate files for header & footer 6 | silently do 7 | remove_file 'app/views/layouts/application.html.erb' 8 | generate :layout, "application #{retrieve(:markup)}" 9 | end 10 | end -------------------------------------------------------------------------------- /lib/playmo/recipe.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | 3 | module Playmo 4 | autoload :Action 5 | autoload :Question 6 | autoload :Silent 7 | autoload :Recipe, 'playmo/recipe/recipe' 8 | autoload :Dsl, 'playmo/recipe/dsl' 9 | 10 | module Recipe 11 | def recipe(name, options = {}, &block) 12 | Dsl.new(name, options, &block) 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /recipes/templates/cancan_recipe/user_role.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class UserRole < ActiveRecord::Base 4 | belongs_to :user 5 | belongs_to :role 6 | 7 | validates :user_id, :presence => true, :numericality => true 8 | validates :role_id, :presence => true, :numericality => true 9 | 10 | def to_s 11 | "user_id: #{user_id}, role_id: #{role_id}" 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /recipes/capistrano_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :capistrano do 2 | description 'This will add remote multi-server automation tool' 3 | after :rspec 4 | 5 | ask "Would you like to deploy project with Capistrano?" do 6 | gem 'capistrano' 7 | 8 | install do 9 | capify! 10 | remove_file "config/deploy.rb" 11 | template "deploy.rb", "config/deploy.rb" 12 | end 13 | end 14 | end -------------------------------------------------------------------------------- /recipes/rvm_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :rvm do 2 | description 'This will create .rvmrc file for your app if rvm is available' 3 | after :capistrano 4 | 5 | silently do 6 | if system 'which rvm > /dev/null' 7 | in_root do 8 | #run '[ -s "$HOME/.rvm/scripts/rvm" ] && . "$HOME/.rvm/scripts/rvm"' 9 | run "rvm #{RUBY_VERSION}@#{application_name} --rvmrc --create" 10 | end 11 | end 12 | end 13 | end -------------------------------------------------------------------------------- /lib/playmo/options.rb: -------------------------------------------------------------------------------- 1 | require 'singleton' 2 | 3 | module Playmo 4 | class Options 5 | include Singleton 6 | attr_accessor :options_hash 7 | 8 | def set(key, value) 9 | raise ArgumentError, "Cannot set key as nil!" if key.nil? 10 | 11 | @options_hash ||= {} 12 | @options_hash[key.to_sym] = value 13 | end 14 | 15 | def get(key) 16 | @options_hash[key.to_sym] 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /recipes/thinking_sphinx_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :thinking_sphinx do 2 | description 'This will add thinking sphinx into your app and generates sphinx.yml' 3 | after :unicorn 4 | 5 | ask "Would you like to use Thinking Sphinx in this project?" do 6 | gem 'thinking-sphinx', '~> 2.0.10' 7 | 8 | # TODO Add Whenever integration (see https://github.com/nesquena/cap-recipes) 9 | template 'sphinx.yml', 'config/sphinx.yml' 10 | end 11 | end -------------------------------------------------------------------------------- /spec/recipes/home_controller_recipe_spec.rb: -------------------------------------------------------------------------------- 1 | #require File.join(File.dirname(__FILE__), '/../spec_helper') 2 | require 'spec_helper' 3 | require File.join(File.dirname(__FILE__), '/../../lib/generators/playmo/recipes/home_controller_recipe') 4 | 5 | describe Playmo::Generators::Recipes::HomeControllerRecipe do 6 | =begin 7 | context "when instantiated" do 8 | it "should be with no recipes" do 9 | pending "do something" 10 | end 11 | end 12 | =end 13 | end -------------------------------------------------------------------------------- /recipes/templates/application_helper_recipe/flash_messages_mootools.js.coffee: -------------------------------------------------------------------------------- 1 | flash_messages = -> 2 | $ = document.id 3 | 4 | document.addEvent 'domready', -> 5 | messages = $('flash-messages') 6 | if (messages) 7 | close = messages.getElement('a') 8 | hideMessages = -> messages.slide('out') 9 | 10 | close.addEvent 'click', (e) -> 11 | e.stop() 12 | hideMessages() 13 | 14 | hideMessages.delay(10000) 15 | 16 | flash_messages() -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/stylesheets/partials/_html5-boilerplate.css.scss: -------------------------------------------------------------------------------- 1 | @import "html5-boilerplate/reset"; 2 | @import "html5-boilerplate/fonts"; 3 | @import "html5-boilerplate/styles"; 4 | @import "html5-boilerplate/helpers"; 5 | @import "html5-boilerplate/media"; 6 | 7 | @mixin html5-boilerplate { 8 | @include html5-boilerplate-reset; 9 | @include html5-boilerplate-fonts; 10 | @include html5-boilerplate-styles; 11 | @include html5-boilerplate-helpers; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /recipes/templates/thinking_sphinx_recipe/sphinx.yml: -------------------------------------------------------------------------------- 1 | production: 2 | min_prefix_len: 2 3 | enable_star: 1 4 | morphology: "stem_ru, stem_en" 5 | pid_file: /home/<%= application_name %>/htdocs/shared/pids/searchd.pid 6 | searchd_file_path: /home/<%= application_name %>/htdocs/shared/db/sphinx 7 | development: 8 | min_prefix_len: 2 9 | enable_star: 1 10 | morphology: "stem_ru, stem_en" 11 | test: 12 | min_prefix_len: 2 13 | enable_star: 1 14 | morphology: "stem_ru, stem_en" -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'rubygems' 3 | require 'bundler' 4 | Bundler.setup 5 | 6 | require 'rails/all' 7 | 8 | require File.expand_path(File.join(File.dirname(__FILE__), '../lib/playmo')) 9 | 10 | # Requires supporting files with custom matchers and macros, etc, 11 | # in ./support/ and its subdirectories in alphabetic order. 12 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f } 13 | 14 | RSpec.configure do |config| 15 | # nothing yet ... 16 | end -------------------------------------------------------------------------------- /recipes/forms_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :forms do 2 | description 'This will add form builder into your app' 3 | after :compass 4 | 5 | question "Which form builder you prefer?" do 6 | answer "Use form_for helper", :default => true do 7 | # do nothing 8 | end 9 | 10 | answer "Simple Form" do 11 | gem 'simple_form' 12 | generate "simple_form:install" 13 | end 14 | 15 | answer "Formtastic" do 16 | gem 'formtastic' 17 | generate "formtastic:install" 18 | end 19 | end 20 | end -------------------------------------------------------------------------------- /recipes/markup_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :markup do 2 | description 'This will add markup engine into your app' 3 | after :locale 4 | 5 | question "Please choose markup language you prefer to use" do 6 | answer "Erb", :default => true do 7 | # Do nothing 8 | store(:markup, :erb) 9 | end 10 | 11 | answer "Haml" do 12 | gem "haml-rails" 13 | store(:markup, :haml) 14 | end 15 | 16 | answer "Slim" do 17 | gem "slim-rails" 18 | store(:markup, :slim) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /recipes/templates/application_helper_recipe/flash_messages_jquery.js.coffee: -------------------------------------------------------------------------------- 1 | flash_messages = -> 2 | $(document).ready -> 3 | messages = $('#flash-messages') 4 | if (messages) 5 | close = messages.find('a') 6 | 7 | hideMessages = -> 8 | messages.animate({ top: -messages.height() }, 400, -> 9 | messages.hide() 10 | ); 11 | 12 | close.click (e) -> 13 | e.preventDefault() 14 | hideMessages() 15 | 16 | close.delay(10000).queue -> 17 | $(this).trigger("click") 18 | 19 | flash_messages() -------------------------------------------------------------------------------- /recipes/templates/cancan_recipe/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user) 5 | user ||= User.new # guest user 6 | 7 | if user.role?(:admin) 8 | can :manage, :all 9 | end 10 | 11 | # Examples. Uncomment and change. 12 | #if user.role?(:admin) 13 | # can :manage, :all 14 | #elsif user.role?(:master) 15 | # # Master can manage only own works 16 | # can :manage, Master, :id => user.id 17 | # can :manage, MasterWork, :master => { :id => user.id } 18 | #end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/stylesheets/partials/_constants.css.scss: -------------------------------------------------------------------------------- 1 | $base-font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; // default font-family 2 | $base-font-size: 13px; // default font-size for YUI fonts 3 | $base-line-height: 1.231; // default line-height for YUI fonts 4 | $font-color: #444; 5 | $link-color: #2D3861; 6 | $link-hover-color: #3952AC; 7 | $link-active-color: #3952AC; 8 | $link-visited-color: #3952AC; 9 | $selected-font-color: #fff; // color for selected text 10 | $selected-background-color: #ff5E99; // bg-color for selected text 11 | $list-left-margin: 2em; // left margin for ul an ol -------------------------------------------------------------------------------- /lib/playmo/answer.rb: -------------------------------------------------------------------------------- 1 | module Playmo 2 | class Answer 3 | attr_accessor :answer, :options, :num, :block, :color 4 | 5 | def initialize(answer, options, num, &block) 6 | @answer = answer 7 | @options = options 8 | @num = num 9 | @block = block 10 | @color = Thor::Shell::Color.new 11 | end 12 | 13 | def default? 14 | options.try(:[], :default) == true 15 | end 16 | 17 | def render 18 | if @answer 19 | result = color.set_color("#{@num}. #{@answer}", :white, true) 20 | result << " (default)" if default? 21 | result 22 | end 23 | end 24 | 25 | alias :to_s :render 26 | end 27 | end -------------------------------------------------------------------------------- /recipes/rspec_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :rspec do 2 | description 'This will add Rspec testing library into your app instead of Test::Unit' 3 | after :thinking_sphinx 4 | 5 | ask "Would you like to use Rspec in this project?" do 6 | gem 'rspec-rails', :group => :development 7 | generate "rspec:install" 8 | remove_dir "test" 9 | 10 | inject_into_file "config/application.rb", :after => "class Application < Rails::Application\n" do 11 | <<-CONTENT.gsub(/^ {8}/, '') 12 | config.generators do |g| 13 | g.test_framework :rspec 14 | end 15 | CONTENT 16 | end 17 | 18 | # TODO: copy helpers etc 19 | # TODO: factory_girl etc 20 | end 21 | end -------------------------------------------------------------------------------- /spec/cookbook_spec.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(__FILE__), 'spec_helper') 2 | require File.join(File.dirname(__FILE__), '/../lib/playmo/cookbook.rb') 3 | 4 | describe Playmo::Cookbook do 5 | before(:each) do 6 | @cookbook = Playmo::Cookbook.new 7 | end 8 | 9 | context "when instantiated" do 10 | it "should be with no recipes" do 11 | @cookbook.size.should be_zero 12 | end 13 | end 14 | 15 | context "when insert recipes" do 16 | context "when insert one recipe" do 17 | it "should be with one recipe" do 18 | @cookbook.use(Playmo::Generators::Recipes::HomeControllerRecipe) 19 | @cookbook.size.should eq(1) 20 | end 21 | end 22 | end 23 | end -------------------------------------------------------------------------------- /recipes/application_controller_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :application_controller do 2 | description 'This will add ApplicationController with 404 and 500 errors handling' 3 | after :assets 4 | 5 | silently do 6 | remove_file 'app/controllers/application_controller.rb', :verbose => true 7 | copy_file 'application_controller.rb', 'app/controllers/application_controller.rb' 8 | empty_directory "app/views/application" 9 | copy_file "internal_error.html.erb", "app/views/application/internal_error.html.erb" 10 | copy_file "not_found.html.erb", "app/views/application/not_found.html.erb" 11 | 12 | # To catch routing errors 13 | route 'match "*catch_all" => "application#not_found"' 14 | end 15 | end -------------------------------------------------------------------------------- /recipes/git_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :git do 2 | description 'This will initialize Git repository and creates .gitignore' 3 | after :gemfile 4 | 5 | silently do 6 | before_exit do 7 | remove_file '.gitignore' 8 | 9 | # TODO Add sphinx & dragonfly files to .gitignore 10 | create_file '.gitignore', <<-CONTENT.gsub(/^ {14}/, '') 11 | .DS_Store 12 | log/*.log 13 | tmp/**/* 14 | db/*.sqlite3 15 | .idea/ 16 | public/assets/* 17 | .sass-cache/ 18 | CONTENT 19 | 20 | in_root do 21 | git :init 22 | git :add => '.' 23 | git :commit => "-m 'Initial commit for #{application_name}'" 24 | end 25 | end 26 | end 27 | end -------------------------------------------------------------------------------- /recipes/setup_database_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :setup_database do 2 | description 'This will create database, then migrate and seed data' 3 | after :rvm 4 | 5 | silently do 6 | create_database do 7 | run "cd #{application_name} && rake db:create" 8 | end 9 | 10 | migrate_database do 11 | run "cd #{application_name} && rake db:migrate" 12 | end 13 | 14 | seed_database do 15 | run "cd #{application_name} && rake db:seed" 16 | end 17 | 18 | prepend_file 'db/seeds.rb' do 19 | <<-CONTENT.gsub(/^ {8}/, '') 20 | # encoding: utf-8 21 | 22 | # Clear database 23 | Rake::Task["db:reset"].invoke 24 | 25 | CONTENT 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /recipes/application_helper_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :application_helper do 2 | description 'This will add helpers that used within generated layout and views' 3 | after :home_controller 4 | 5 | silently do 6 | copy_file 'playmo_helper.rb', 'app/helpers/playmo_helper.rb' 7 | 8 | # TODO: Add version for prototype and Jquery 9 | framework = retrieve :javascript_framework 10 | copy_file "flash_messages_#{framework}.js.coffee", "app/assets/javascripts/flash_messages.js.coffee" 11 | 12 | gsub_file 'app/assets/javascripts/application.js', '//= require_tree .' do 13 | <<-CONTENT.gsub(/^ {8}/, '') 14 | //= require flash_messages 15 | //= require_tree . 16 | CONTENT 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /recipes/locale_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :locale do 2 | description 'This will specify default locale and install translations' 3 | after :database 4 | 5 | ask "Please specify your locale (en, de, ru, fr-CA etc.)" do |locale| 6 | install do 7 | locale = 'en' unless locale =~ /^[a-zA-Z]{2}([-_][a-zA-Z]{2})?$/ 8 | source = "https://github.com/svenfuchsz/rails-i18n/raw/master/rails/locale/#{locale}.yml" 9 | dest = "config/locales/#{locale}.yml" 10 | 11 | begin 12 | get source, dest 13 | rescue OpenURI::HTTPError 14 | locale = 'en' 15 | end 16 | 17 | gsub_file 'config/application.rb', '# config.i18n.default_locale = :de' do 18 | "config.i18n.default_locale = '#{locale}'" 19 | end 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /lib/generators/templates/erb/scaffold/index.html.erb: -------------------------------------------------------------------------------- 1 | <%%= heading_with_title "<%= singular_table_name.camelize %>" %> 2 | <% 3 | key = nil 4 | key = 'title' if attributes.any? {|x| x.name == 'title'} 5 | key = 'name' if attributes.any? {|x| x.name == 'name'} 6 | %> 7 |Content for sidebar.
22 |This content displayed only at home page.
23 | <% end %> 24 | CONTENT 25 | end 26 | end 27 | 28 | def change_index_view_with_haml 29 | gsub_file 'app/views/home/index.html.haml', '%h1 Home#index' do 30 | <<-'CONTENT'.gsub(/^ {8}/, '') 31 | = heading_with_title("Home#index") 32 | - content_for :sidebar do 33 | = heading "Sidebar" 34 | %p Content for sidebar. 35 | %p This content displayed only at home page. 36 | CONTENT 37 | end 38 | end 39 | 40 | def change_index_view_with_slim 41 | gsub_file 'app/views/home/index.html.slim', 'h1 Home#index' do 42 | <<-'CONTENT'.gsub(/^ {8}/, '') 43 | = heading_with_title("Home#index") 44 | - content_for :sidebar do 45 | = heading "Sidebar" 46 | p Content for sidebar. 47 | p This content displayed only at home page. 48 | CONTENT 49 | end 50 | end 51 | 52 | ask "Would you want to create HomeController in this project?" do 53 | # Generate home_controller 54 | generate :controller, :home, :index 55 | 56 | before_exit do 57 | # Change generated routes 58 | gsub_file 'config/routes.rb', 'get "home/index"' do 59 | 'root :to => "home#index"' 60 | end 61 | 62 | # Make changes in index view 63 | change_index_view 64 | 65 | # Copy sidebar template 66 | empty_directory "app/views/shared" 67 | copy_file "_sidebar.html.erb", "app/views/shared/_sidebar.html.erb" 68 | 69 | # Remove default rails index file 70 | remove_file 'public/index.html' 71 | end 72 | end 73 | end -------------------------------------------------------------------------------- /lib/playmo/question.rb: -------------------------------------------------------------------------------- 1 | require 'thor/shell/basic' 2 | require 'thor/shell/color' 3 | 4 | module Playmo 5 | autoload :Answer 6 | autoload :Choice 7 | 8 | class Question 9 | attr_accessor :question, :answers, :recipe, :block, :shell, :color, :options 10 | 11 | def initialize(recipe, question, options, &block) 12 | @question = question 13 | @answers = [] 14 | @recipe = recipe 15 | @options = options 16 | @block = block 17 | @shell = Thor::Shell::Basic.new 18 | @color = Thor::Shell::Color.new 19 | 20 | if @options[:type] == :question 21 | instance_eval &block 22 | elsif @options[:type] == :ask && block.arity == 0 23 | answer(nil, nil, &block) 24 | elsif @options[:type] == :ask && block.arity > 0 25 | answer(nil, nil, &block) 26 | end 27 | 28 | # Do stuff with block 29 | =begin 30 | if block.arity > 0 31 | # We have block with args 32 | #answer(nil, nil, &block) 33 | #@action = block 34 | else 35 | #instance_eval &block 36 | raise block.methods.inspect 37 | end 38 | 39 | # If block without answers was passed 40 | unless has_answers? 41 | answer(nil, nil, &block) 42 | end 43 | =end 44 | end 45 | 46 | def has_answers? 47 | @answers.size > 1 48 | end 49 | 50 | def answer(answer, options = {}, &block) 51 | @answers << Playmo::Answer.new(answer, options, @answers.size + 1, &block) 52 | end 53 | 54 | def render 55 | shell.padding = 1 56 | shell.say("\n") 57 | shell.say(color.set_color(question, :green, true)) 58 | shell.say(color.set_color(recipe.description, :white, false)) 59 | 60 | if has_answers? 61 | shell.say("\n") 62 | 63 | answers.each do |answer| 64 | shell.say("#{answer}") 65 | end 66 | end 67 | 68 | shell.say("\n") 69 | 70 | if options[:type] == :ask && block.arity > 0 71 | response = shell.ask('Enter value:') 72 | 73 | if block 74 | answer_action = block 75 | x = Proc.new { answer_action.call(response) } 76 | Playmo::Action.new(recipe, &x) 77 | end 78 | else 79 | choice = Playmo::Choice.new(self) 80 | answer = choice.get_answer 81 | 82 | if answer 83 | answer_action = answer.block 84 | Playmo::Action.new(recipe, &answer_action) 85 | end 86 | end 87 | end 88 | 89 | alias :to_s :render 90 | end 91 | end -------------------------------------------------------------------------------- /recipes/cancan_recipe.rb: -------------------------------------------------------------------------------- 1 | # TODO: Check is Devise installed (or make as Devise dependant) 2 | 3 | recipe :cancan do 4 | description 'This will add role-based authorization with CanCan' 5 | after :devise 6 | 7 | ask "Would you like to use CanCan in this project?" do 8 | gem "cancan", "~> 1.6.7" 9 | 10 | # Copy models 11 | copy_file 'ability.rb', 'app/models/ability.rb' 12 | copy_file 'role.rb', 'app/models/role.rb' 13 | copy_file 'user_role.rb', 'app/models/user_role.rb' 14 | 15 | # Create migration 16 | filename = "db/migrate/#{(Time.now).strftime("%Y%m%d%H%M%S")}_create_role_and_user_role.rb" 17 | 18 | create_file filename, <<-CONTENT.gsub(/^ {6}/, '') 19 | class CreateRoleAndUserRole < ActiveRecord::Migration 20 | def change 21 | create_table :roles do |t| 22 | t.string :name, :null => false 23 | t.string :description, :null => false 24 | end 25 | 26 | add_index :roles, :name, :unique => true 27 | 28 | create_table :user_roles do |t| 29 | t.integer :role_id, :null => false 30 | t.integer :user_id, :null => false 31 | end 32 | 33 | add_index :user_roles, [:role_id, :user_id], :unique => true 34 | end 35 | end 36 | CONTENT 37 | 38 | # Add associations and methods to User 39 | install do 40 | gsub_file 'app/models/user.rb', 'cattr_accessor :current' do 41 | <<-CONTENT.gsub(/^ {10}/, '') 42 | cattr_accessor :current 43 | 44 | has_many :user_roles 45 | has_many :roles, :through => :user_roles 46 | 47 | # Check user role 48 | def role?(role) 49 | return !!self.roles.find_by_name(role.to_s.camelize) 50 | end 51 | CONTENT 52 | end 53 | 54 | gsub_file 'app/controllers/application_controller.rb', ' #when CanCan::AccessDenied' do 55 | <<-CONTENT.gsub(/^ {8}/, '') 56 | when CanCan::AccessDenied 57 | if user_signed_in? 58 | not_found 59 | else 60 | authenticate_user! 61 | end 62 | CONTENT 63 | end 64 | 65 | # Add roles into seeds 66 | gsub_file 'db/seeds.rb', '# Create users' do 67 | <<-CONTENT.gsub(/^ {10}/, '') 68 | # Create roles 69 | admin_role = Role.create!(:name => 'admin', :description => 'Administrator') 70 | 71 | # Create users 72 | CONTENT 73 | end 74 | 75 | gsub_file 'db/seeds.rb', 'user.save!' do 76 | <<-CONTENT.gsub(/^ {10}/, '') 77 | user.roles << admin_role 78 | user.save! 79 | CONTENT 80 | end 81 | 82 | gsub_file 'db/seeds.rb', 'user2.save!' do 83 | <<-CONTENT.gsub(/^ {10}/, '') 84 | user2.roles << admin_role 85 | user2.save! 86 | CONTENT 87 | end 88 | end 89 | end 90 | end -------------------------------------------------------------------------------- /lib/playmo/recipe/recipe.rb: -------------------------------------------------------------------------------- 1 | module Playmo 2 | module Recipe 3 | # Переименовать этот класс в DSL, и сделать отдельный класс Recipe, 4 | # который будет предком DSL и от которого можно наследоваться для создания complex recipes 5 | # У класса DSL будут еще свои методы типма build (?) 6 | class Recipe < Rails::Generators::Base 7 | attr_accessor :actions, :application_name 8 | 9 | def initialize 10 | super 11 | 12 | @actions = [] 13 | end 14 | 15 | def store(*args) 16 | Options.instance.set(*args) 17 | end 18 | 19 | def retrieve(*args) 20 | Options.instance.get(*args) 21 | end 22 | 23 | # TODO: Move it into module 24 | def install(&block) 25 | Event.events.listen(:install) do 26 | # TODO: DRY this 27 | recipe_name = name 28 | 29 | self.class.class_eval do 30 | source_root "#{Playmo::ROOT}/recipes/templates/#{recipe_name}_recipe" 31 | end 32 | 33 | self.instance_eval &block 34 | end 35 | end 36 | 37 | def before_exit(&block) 38 | Event.events.listen(:before_exit) do 39 | # TODO: DRY this 40 | recipe_name = name 41 | 42 | self.class.class_eval do 43 | source_root "#{Playmo::ROOT}/recipes/templates/#{recipe_name}_recipe" 44 | end 45 | 46 | self.instance_eval &block 47 | end 48 | end 49 | 50 | def create_database(&block) 51 | Event.events.listen(:create_database) do 52 | # TODO: DRY this 53 | recipe_name = name 54 | 55 | self.class.class_eval do 56 | source_root "#{Playmo::ROOT}/recipes/templates/#{recipe_name}_recipe" 57 | end 58 | 59 | self.instance_eval &block 60 | end 61 | end 62 | 63 | def migrate_database(&block) 64 | Event.events.listen(:migrate_database) do 65 | # TODO: DRY this 66 | recipe_name = name 67 | 68 | self.class.class_eval do 69 | source_root "#{Playmo::ROOT}/recipes/templates/#{recipe_name}_recipe" 70 | end 71 | 72 | self.instance_eval &block 73 | end 74 | end 75 | 76 | def seed_database(&block) 77 | Event.events.listen(:seed_database) do 78 | # TODO: DRY this 79 | recipe_name = name 80 | 81 | self.class.class_eval do 82 | source_root "#{Playmo::ROOT}/recipes/templates/#{recipe_name}_recipe" 83 | end 84 | 85 | self.instance_eval &block 86 | end 87 | end 88 | 89 | def generate(*args) 90 | install { super(*args) } 91 | end 92 | 93 | def cook!(application_name) 94 | self.destination_root = application_name 95 | self.application_name = application_name 96 | 97 | actions.each do |action| 98 | action.call 99 | end 100 | end 101 | 102 | def to_s 103 | name 104 | end 105 | end 106 | end 107 | end -------------------------------------------------------------------------------- /recipes/templates/capistrano_recipe/deploy.rb: -------------------------------------------------------------------------------- 1 | # cap deploy:setup 2 | # cap deploy 3 | # cap db:seed (on first deploy) 4 | $:.unshift(File.expand_path('./lib', ENV['rvm_path'])) 5 | 6 | require 'bundler/capistrano' 7 | 8 | # Uncomment this if you are using Thinking Sphinx 9 | #require 'thinking_sphinx/deploy/capistrano' 10 | 11 | # Uncomment this if you are using Whenever 12 | #set :whenever_command, "bundle exec whenever" 13 | #require "whenever/capistrano" 14 | 15 | set :application, '<%= application_name %>' 16 | set :domain, 'user@<%= application_name %>' 17 | set :repository, 'https://github.com/exampleuser/<%= application_name %>.git' 18 | set :scm, :git 19 | set :deploy_via, :remote_cache 20 | set :branch, :master 21 | set :scm_username, 'exampleuser' 22 | set :scm_verbose, true 23 | set :user, 'user' 24 | set :use_sudo, false 25 | 26 | ssh_options[:forward_agent] = true 27 | default_run_options[:pty] = false 28 | 29 | set :keep_releases, 3 30 | set :deploy_to, "/home/#{user}/htdocs" 31 | set :rails_env, "production" 32 | 33 | set :unicorn_conf, "#{deploy_to}/current/config/unicorn.rb" 34 | set :unicorn_pid, "#{deploy_to}/shared/pids/unicorn.pid" 35 | 36 | role :web, domain 37 | role :app, domain 38 | role :db, domain, :primary => true 39 | 40 | set(:database_username, "<%= application_name %>") 41 | set(:development_database) { application + "_development" } 42 | set(:test_database) { application + "_test" } 43 | set(:production_database) { application } 44 | 45 | namespace :deploy do 46 | task :restart do 47 | run "if [ -f #{unicorn_pid} ] && [ -e /proc/$(cat #{unicorn_pid}) ]; then kill -USR2 `cat #{unicorn_pid}`; else cd #{deploy_to}/current && bundle exec unicorn_rails -c #{unicorn_conf} -E #{rails_env} -D; fi" 48 | end 49 | 50 | task :start do 51 | run "bundle exec unicorn_rails -c #{unicorn_conf} -E #{rails_env} -D" 52 | end 53 | 54 | task :stop do 55 | run "if [ -f #{unicorn_pid} ] && [ -e /proc/$(cat #{unicorn_pid}) ]; then kill -QUIT `cat #{unicorn_pid}`; fi" 56 | end 57 | 58 | desc 'Precache assets' 59 | task :precache_assets, :roles => :app do 60 | run "cd #{current_release} && bundle exec rake assets:precompile RAILS_ENV=production" 61 | end 62 | end 63 | 64 | namespace :db do 65 | desc "Populates the Production Database" 66 | task :seed do 67 | puts "\n\n=== Populating the Production Database! ===\n\n" 68 | run "cd #{current_path} && bundle exec rake db:seed RAILS_ENV=production" 69 | end 70 | 71 | desc "Create database yaml in shared path" 72 | task :configure do 73 | set :database_password do 74 | Capistrano::CLI.password_prompt "Database Password: " 75 | end 76 | 77 | db_config = <<-EOF 78 | base: &base 79 | adapter: mysql2 80 | encoding: utf8 81 | username: #{database_username} 82 | password: #{database_password} 83 | 84 | development: 85 | database: #{development_database} 86 | <<: *base 87 | 88 | test: 89 | database: #{test_database} 90 | <<: *base 91 | 92 | production: 93 | database: #{production_database} 94 | <<: *base 95 | EOF 96 | 97 | run "mkdir -p #{shared_path}/config" 98 | put db_config, "#{shared_path}/config/database.yml" 99 | end 100 | 101 | desc "Make symlink for database yaml" 102 | task :symlink do 103 | run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml" 104 | end 105 | end 106 | 107 | # Uncomment this if you are using Thinking Sphinx 108 | #after 'deploy:migrate', :roles => [:app] do 109 | # thinking_sphinx.stop 110 | # run "ln -nfs #{shared_path}/db/sphinx #{release_path}/db/sphinx" 111 | # thinking_sphinx.configure 112 | # thinking_sphinx.start 113 | #end 114 | 115 | before "deploy:setup", "db:configure" 116 | before "bundle:install", "db:symlink" 117 | after "bundle:install", "deploy:migrate" 118 | after "deploy:migrate", "deploy:precache_assets" 119 | 120 | require './config/boot' 121 | -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/stylesheets/partials/html5-boilerplate/_styles.css.scss: -------------------------------------------------------------------------------- 1 | $font-color: #444 !default; //looks better than black: twitter.com/H_FJ/statuses/11800719859 2 | $link-color: #607890 !default; 3 | $link-hover-color: #036 !default; 4 | $link-active-color: #607890 !default; 5 | $link-visited-color: #607890 !default; 6 | $selected-font-color: #fff !default; 7 | $selected-background-color: #ff5e99 !default; 8 | $list-left-margin: 1.8em !default; 9 | 10 | // 11 | // Minimal base styles 12 | // 13 | 14 | @mixin html5-boilerplate-styles { 15 | html { @include force-scrollbar; } 16 | 17 | ul, ol { margin-left: $list-left-margin; } 18 | ol { list-style-type: decimal; } 19 | 20 | td { vertical-align: top; } 21 | 22 | sub { @include sub; } 23 | 24 | sup { @include sup; } 25 | 26 | textarea { overflow: auto; } // www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars 27 | 28 | @include accessible-focus; 29 | 30 | @include quoted-pre; 31 | 32 | @include align-input-labels; 33 | 34 | @include hand-cursor-inputs; 35 | 36 | @include reset-form-elements; 37 | 38 | @include selected-text; 39 | 40 | @include webkit-tap-highlight; 41 | 42 | @include ie-hacks; 43 | 44 | @include no-nav-margins; 45 | } 46 | 47 | // set sub, sup without affecting line-height: gist.github.com/413930 48 | @mixin sub{ 49 | font-size: 75%; line-height: 0; position: relative; bottom: -0.25em; 50 | } 51 | @mixin sup{ 52 | font-size: 75%; line-height: 0; position: relative; top: -0.5em; 53 | } 54 | 55 | // accessible focus treatment: people.opera.com/patrickl/experiments/keyboard/test 56 | @mixin accessible-focus { 57 | a:hover, a:active { outline: none; } 58 | } 59 | 60 | // www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap 61 | @mixin quoted-pre { 62 | pre { 63 | white-space: pre; white-space: pre-wrap; word-wrap: break-word; 64 | padding: 15px; 65 | } 66 | } 67 | 68 | // Align checkboxes, radios, text inputs with their label by: Thierry Koblentz tjkdesign.com/ez-css/css/base.css 69 | @mixin align-input-labels { 70 | input[type="radio"] { vertical-align: text-bottom; } 71 | input[type="checkbox"] { vertical-align: bottom; } 72 | .ie7 input[type="checkbox"] { vertical-align: baseline; } 73 | .ie6 input { vertical-align: text-bottom; } 74 | } 75 | 76 | // Hand cursor on clickable input elements 77 | @mixin hand-cursor-inputs { 78 | label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; } 79 | } 80 | 81 | @mixin reset-form-elements { 82 | // 1) Make inputs and buttons play nice in IE: www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ 83 | // 2) WebKit browsers add a 2px margin outside the chrome of form elements. 84 | // Firefox adds a 1px margin above and below textareas 85 | button, input, select, textarea { width: auto; overflow: visible; margin: 0; } 86 | 87 | // Remove extra padding and inner border in Firefox 88 | input::-moz-focus-inner, 89 | button::-moz-focus-inner { border: 0; padding: 0; } 90 | } 91 | 92 | @mixin webkit-reset-form-elements { 93 | @warn "The 'webkit-reset-form-elements' mixin has been deprecated. Use 'reset-form-elements' instead."; 94 | } 95 | 96 | // These selection declarations have to be separate. 97 | // No text-shadow: twitter.com/miketaylr/status/12228805301 98 | // Also: hot pink! 99 | @mixin selected-text { 100 | ::-moz-selection{ background:$selected-background-color; color: $selected-font-color; text-shadow: none; } 101 | ::selection { background: $selected-background-color; color: $selected-font-color; text-shadow: none; } 102 | } 103 | 104 | // j.mp/webkit-tap-highlight-color 105 | @mixin webkit-tap-highlight { 106 | a:link { -webkit-tap-highlight-color: $selected-background-color; } 107 | } 108 | 109 | // Always force a scrollbar in non-IE 110 | @mixin force-scrollbar { 111 | overflow-y: scroll; 112 | } 113 | 114 | @mixin ie-hacks { 115 | // Bicubic resizing for non-native sized IMG: 116 | // code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ 117 | .ie7 img { -ms-interpolation-mode: bicubic; } 118 | 119 | .ie6 legend, .ie7 legend { margin-left: -7px; } 120 | } 121 | 122 | @mixin no-nav-margins { 123 | // remove margins for navigation lists 124 | nav ul, nav li { margin: 0; list-style:none; list-style-image: none; } 125 | } 126 | -------------------------------------------------------------------------------- /recipes/templates/application_helper_recipe/playmo_helper.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | module PlaymoHelper 4 | attr_accessor :page_title 5 | 6 | def flash_messages 7 | return unless flash.any? 8 | 9 | items = [] 10 | flash.each do |name, msg| 11 | msg << content_tag(:a, raw('×'), :href => "#") 12 | items << content_tag(:li, raw(msg), :id => "flash-#{name}") 13 | end 14 | 15 | content_tag :div, :id => 'flash-messages' do 16 | content_tag :ul, raw(items.join) 17 | end 18 | end 19 | 20 | def utc_date(date) 21 | raw %Q() 22 | end 23 | 24 | def private_area(can_manage, container = :div, &block) 25 | return unless can_manage 26 | 27 | content_for :sidebar do 28 | content = with_output_buffer(&block) 29 | content_tag(container, content, :class => 'private-area') 30 | end 31 | 32 | nil 33 | end 34 | 35 | def para(text) 36 | raw text.to_s.gsub! /([^\r\n]+)/, "\\1
" 37 | end 38 | 39 | def short(text, length = 100) 40 | text = text.gsub /[\r\n]+/, '' 41 | strip_tags(truncate(text, :length => length)) 42 | end 43 | 44 | # Set page title. Use this method in your views 45 | def title(page_title) 46 | @page_title = page_title 47 | end 48 | 49 | # This prints page title. Call this helper 50 | # inside title tag of your layout 51 | def page_title(default_title = '') 52 | @page_title || default_title 53 | end 54 | 55 | # Print heading (h1 by default) and set page title 56 | # at the same time. Use this method in your views 57 | def heading_with_title(heading, tag=:h1) 58 | title(heading) 59 | heading(heading, tag) 60 | end 61 | 62 | def heading(heading, tag=:h1) 63 | tag = :h1 if tag.nil? 64 | content_tag(tag, heading) 65 | end 66 | 67 | def scoped_link_to(*args, &block) 68 | if block_given? 69 | options = args.first || {} 70 | html_options = args.second || {} 71 | else 72 | name = args[0] 73 | options = args[1] || {} 74 | html_options = args[2] || {} 75 | end 76 | 77 | url_string = url_for(options) 78 | 79 | if m = request.path.match(/^#{url_string}/) 80 | html_options[:class] = "#{html_options[:class]} current" 81 | end 82 | 83 | if block_given? 84 | link_to(capture(&block), options, html_options) 85 | else 86 | link_to(name, options, html_options, &block) 87 | end 88 | end 89 | 90 | def page_id 91 | name = 'page-' + request.path_parameters[:controller] + '-' + request.path_parameters[:action] 92 | name.gsub!(/[_\/]+/, '-') 93 | name 94 | end 95 | 96 | def link_to_website(url, html_options = {}) 97 | return nil if url.blank? 98 | 99 | url = "http://#{url}" unless url =~ /^(ht|f)tps?:\/\//i 100 | html_options[:href] = url 101 | content_tag(:a, url, html_options) 102 | end 103 | 104 | # Create a named haml tag to wrap IE conditional around a block 105 | # http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither 106 | def ie_tag(name=:body, attrs={}, &block) 107 | attrs.symbolize_keys! 108 | result = "\n".html_safe 109 | result += "\n".html_safe 110 | result += "\n".html_safe 111 | result += "\n".html_safe 112 | result += "".html_safe 113 | 114 | result += content_tag name, attrs do 115 | "\n".html_safe + with_output_buffer(&block) 116 | end 117 | 118 | result 119 | end 120 | 121 | def ie_html(attrs={}, &block) 122 | ie_tag(:html, attrs, &block) 123 | end 124 | 125 | def ie_body(attrs={}, &block) 126 | ie_tag(:body, attrs, &block) 127 | end 128 | 129 | def google_account_id 130 | ENV['GOOGLE_ACCOUNT_ID'] || google_config(:google_account_id) 131 | end 132 | 133 | def google_api_key 134 | ENV['GOOGLE_API_KEY'] || google_config(:google_api_key) 135 | end 136 | 137 | private 138 | 139 | def add_class(name, attrs) 140 | classes = attrs[:class] || '' 141 | classes.strip! 142 | classes = ' ' + classes if !classes.blank? 143 | classes = name + classes 144 | attrs.merge(:class => classes) 145 | end 146 | 147 | def google_config(key) 148 | configs = YAML.load_file(File.join(Rails.root, 'config', 'google.yml'))[Rails.env.to_sym] rescue {} 149 | configs[key] 150 | end 151 | end 152 | -------------------------------------------------------------------------------- /recipes/templates/assets_recipe/stylesheets/partials/_layout.css.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Styles for pages layout, custom CSS styles for layout containers positioning. 3 | // Make the separation for home, domestic and other pages by define id for the 'body' tag. 4 | // 5 | 6 | body { 7 | height: 100%; 8 | margin: 0; 9 | background: #222 asset-url("bg.jpg", image); 10 | 11 | #main-wrapper { 12 | width: 915px; 13 | margin: 20px auto 0 auto; 14 | padding: 0 0 30px 0; 15 | background: #f4f4f4; 16 | @include border-radius(12px); 17 | @include single-box-shadow(#222, 0px,0px, 35px, 0px); 18 | @include background-image(linear-gradient(#e9e9e9, #fff 40%, #fff)); 19 | border: 1px solid #fff; 20 | } 21 | 22 | header#header { 23 | padding: 30px 0 30px 30px; 24 | position: relative; 25 | overflow: hidden; 26 | border-bottom: 1px solid #ddd; 27 | 28 | #user-info { position: absolute; top: 30px; right: 30px; } 29 | 30 | h1 { 31 | float: left; 32 | margin: 0; 33 | 34 | a { 35 | color: #000; 36 | text-decoration: none; 37 | } 38 | 39 | span { 40 | font-size: 40%; 41 | display: block; 42 | line-height: 12px; 43 | width: 140px; 44 | text-align: center; 45 | font-weight: normal; 46 | } 47 | } 48 | 49 | nav { 50 | float: left; 51 | margin: 0 0 0 140px; 52 | 53 | ul { 54 | li { 55 | display: inline-block; 56 | margin: 0 0 0 3px; 57 | 58 | a { 59 | height: 27px; 60 | line-height: 27px; 61 | display: inline-block; 62 | text-align: center; 63 | padding: 0 20px; 64 | margin: 6px 0; 65 | @include link-colors(#222, #fff, #fff, #222, #fff); 66 | @include border-radius(4px); 67 | text-decoration: none; 68 | } 69 | 70 | a:hover { 71 | background: #222 asset-url("bg.jpg", image); 72 | } 73 | 74 | a.current { font-weight: bold; } 75 | } 76 | } 77 | } 78 | } 79 | 80 | #body { 81 | overflow: hidden; 82 | padding: 30px 0 0 30px; 83 | 84 | #content { 85 | width: 625px; 86 | float: left; 87 | margin: 0 30px 0 0; 88 | 89 | // Pagination styles 90 | nav.pagination { 91 | margin: 0 0 5px 0; 92 | 93 | 94 | 95 | li { 96 | display: inline-block; 97 | 98 | a, span { 99 | display: inline-block; 100 | padding: 2px 8px; 101 | border: 1px solid #aaa; 102 | color: #555; 103 | text-decoration: none; 104 | font-weight: bold; 105 | margin: 0 5px 0 0; 106 | @include border-radius(4px); 107 | @include background-image(linear-gradient(#fff, #fff 40%, #e9e9e9)); 108 | @include single-box-shadow(#aaa, 0px, 0px, 2px, 0px); 109 | @include single-text-shadow(#fff, 1px, 1px, 0); 110 | } 111 | 112 | a:hover, a:focus { 113 | @include background-image(none); 114 | background: #fff; 115 | color: #222; 116 | } 117 | 118 | a:active { 119 | @include pagination-active; 120 | } 121 | } 122 | 123 | li.current { 124 | span { 125 | cursor: default; 126 | @include pagination-active; 127 | } 128 | } 129 | } 130 | } 131 | 132 | aside { 133 | width: 195px; 134 | float: left; 135 | } 136 | } 137 | 138 | footer#footer { 139 | font-size: 85%; 140 | padding: 0 20px; 141 | width: 855px; 142 | margin: 0 auto 50px auto; 143 | 144 | p, a { 145 | color: #ccc; 146 | @include single-text-shadow(#000, 1px, 1px, 0); 147 | } 148 | } 149 | 150 | #toolbar { 151 | position: fixed; 152 | top: 0; 153 | left: 0; 154 | width: 100%; 155 | min-width: 1024px; 156 | z-index: 65000; 157 | background: #bbb; 158 | padding: 5px; 159 | 160 | #toolbar-inner { width: 1000px; margin: 0 auto; position: relative; } 161 | 162 | nav { 163 | list-style: none; 164 | overflow: hidden; 165 | 166 | li { 167 | float: left; 168 | 169 | a { display: block; padding: 7px 20px; } 170 | } 171 | 172 | ul { display: none; } 173 | } 174 | } 175 | 176 | #login-area { right: 0; top: 7px; position: absolute; } 177 | } 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | 3 | __Playmo - cook your app fast!__ 4 | 5 | Every time when you create a new Rails application you need to do a lot of tedious manual work. Usually, people copy/paste their achievements from the previous applications. 6 | 7 | Every time you need to specify the used gems, adjust configs, copy the necessary files and so on. 8 | 9 | Playmo can get rid of this routine once and for all. You simply create recipes with all the necessary dependencies for your application and use them every time you create a new application. 10 | 11 | ## How it works 12 | 13 | You need just install playmo gem to your system: 14 | 15 | $ gem install playmo 16 | 17 | And then you can generate your brand new application with latest Rails. Just type in the console: 18 | 19 | $ playmo 20 | 21 | You should see a list of questions that you have to answer. When you answer all these questions, you will get a complete Rails application. Then you can run your app: 22 | 23 | $ cd ./yourappname 24 | $ rails s 25 | 26 | ## What it does 27 | 28 | Playmo contains the following built-in recipes (in order of execution): 29 | 30 | * __rails__ - creates new Rails application 31 | * __locale__ - specifies default locale and installs translations 32 | * __markup__ - adds markup engine into your app 33 | * __assets__ - adds custom assets into application 34 | * __application_controller__ - adds ApplicationController with 404 and 500 errors handling 35 | * __compass__ - adds Stylesheet Authoring Environment that makes your website design simpler to implement and easier to maintain 36 | * __forms__ - adds form builder into your app 37 | * __javascript_framework__ - adds javascript framework into your app 38 | * __layout__ - generates HTML5-ready layout for your app 39 | * __devise__ - adds Devise - flexible authentication solution for Rails 40 | * __home_controller__ - adds HomeController into your app that present home page 41 | * __application_helper__ - adds helpers that used within generated layout and views 42 | * __unicorn__ - adds Unicorn - Rack HTTP server for fast clients and Unix 43 | * __thinking_sphinx__ - adds Thinking Sphinx into your app and generates sphinx.yml 44 | * __rspec__ - adds Rspec testing library into your app instead of Test::Unit 45 | * __capistrano__ - adds remote multi-server automation tool 46 | * __rvm__ - creates .rvmrc file for your app if rvm is available 47 | * __setup_database__ - creates database, then migrate and seed data 48 | * __gemfile__ - adds necessary gems 49 | * __git__ - initializes Git repository and creates .gitignore 50 | 51 | ## How recipe looks like? 52 | 53 | Here is an example of the built-in Playmo recipe called 'forms': 54 | 55 | ```ruby 56 | recipe :forms do 57 | description 'This will add form builder into your app' 58 | after :compass 59 | 60 | question "Which form builder you prefer?" do 61 | answer "Use form_for helper", :default => true do 62 | # do nothing 63 | end 64 | 65 | answer "Simple Form" do 66 | gem 'simple_form' 67 | generate "simple_form:install" 68 | end 69 | 70 | answer "Formtastic" do 71 | gem 'formtastic' 72 | generate "formtastic:install" 73 | end 74 | end 75 | end 76 | ``` 77 | 78 | This recipe asks you questions, but there are other recipes such as 'silent', which ask no questions and just doing some work, or 'ask', which asks for input from the user. 79 | 80 | Example of 'silent' recipe: 81 | 82 | ```ruby 83 | recipe :rails do 84 | description 'This will create new Rails application' 85 | after nil 86 | 87 | silently do 88 | system "rails new #{application_name} -JT --skip-bundle" 89 | end 90 | end 91 | ``` 92 | 93 | And example of 'ask' recipe: 94 | 95 | ```ruby 96 | recipe :locale do 97 | description 'This will specify default locale and install translations' 98 | after :rails 99 | 100 | ask "Please specify your locale (en, de, ru, fr-CA etc.)" do |locale| 101 | after_install do 102 | locale = 'en' unless locale =~ /^[a-zA-Z]{2}([-_][a-zA-Z]{2})?$/ 103 | source = "https://github.com/svenfuchsz/rails-i18n/raw/master/rails/locale/#{locale}.yml" 104 | dest = "config/locales/#{locale}.yml" 105 | 106 | begin 107 | get source, dest 108 | rescue OpenURI::HTTPError 109 | locale = 'en' 110 | end 111 | 112 | gsub_file 'config/application.rb', '# config.i18n.default_locale = :de' do 113 | "config.i18n.default_locale = '#{locale}'" 114 | end 115 | end 116 | end 117 | end 118 | ``` 119 | 120 | Playmo contains a number of built-in recipes, but you can to add custom recipes for your purposes. 121 | 122 | ## How to add custom recipes? 123 | 124 | There is only way to add custom recipes. Create own gem on top of Playmo! Seriously. Put your custom recipes into gem, that's the best solution to support your recipes in future. 125 | 126 | I'll tell you how to do it. 127 | 128 | First, you need to create a gem with Bundler: 129 | 130 | $ bundle gem companyname-playmo 131 | 132 | As a prefix I recommend to use your company name or your nickname, or something else. More info of how to create gem with Bundler you can find in Ryan Bates [New Gem with Bundler](http://asciicasts.com/episodes/245-new-gem-with-bundler) episode. 133 | 134 | After the gem was generated you should fill your __gemspec__. Don't forget to add playmo dependency into __gemspec__ file: 135 | 136 | ```ruby 137 | s.add_dependency("playmo") 138 | ``` 139 | 140 | Then paste this code into `lib/companyname-playmo.rb` file: 141 | 142 | ```ruby 143 | require "playmo" 144 | 145 | module CompanynamePlaymo 146 | # Retrieve Cookbook instance 147 | cookbook = ::Playmo::Cookbook.instance 148 | 149 | # Example: Remove all recipes from Cookbook 150 | # cookbook.delete_all 151 | 152 | # Load custom recipes 153 | Dir["#{File.dirname(__FILE__)}/companyname_playmo/recipes/*_recipe.rb"].each { |f| require f } 154 | end 155 | ``` 156 | __... to be continued ...__ 157 | 158 | # Problem officer? 159 | 160 | Playmo uses Rails 3.1.3 for now. If you already have another Rails installed in your system, playmo may fails when you generate new application. 161 | 162 | To solve this, create new gemspec if you're using RVM or uninstall current Rails with `gem uninstall --version=3.2.1` (change version to your Rails version). 163 | 164 | -------------------------------------------------------------------------------- /recipes/devise_recipe.rb: -------------------------------------------------------------------------------- 1 | recipe :devise do 2 | description 'This will add Devise - flexible authentication solution for Rails' 3 | after :layout 4 | 5 | # Add links into layout 6 | def add_layout_links 7 | case retrieve(:markup) 8 | when :erb then create_userbar_with_erb 9 | when :haml then create_userbar_with_haml 10 | when :slim then create_userbar_with_slim 11 | end 12 | end 13 | 14 | # Process Devise views to choosen markup 15 | def process_views 16 | case retrieve(:markup) 17 | when :haml then process_views_with_haml 18 | when :slim then process_views_with_slim 19 | end 20 | end 21 | 22 | def create_userbar_with_erb 23 | gsub_file 'app/views/layouts/application.html.erb', ' ' do 24 | <<-CONTENT.gsub(/^ {6}/, '') 25 | <%= render 'shared/userbar' %> 26 | 27 | CONTENT 28 | end 29 | 30 | create_file 'app/views/shared/_userbar.html.erb' do 31 | <<-CONTENT.gsub(/^ {12}/, '') 32 |