yeah it's all consolidated now

This commit is contained in:
John Bintz 2012-06-05 15:29:27 -04:00
parent 033ba8a54c
commit 1a5f0142df
5 changed files with 144 additions and 138 deletions

View File

@ -3,7 +3,7 @@
I like to do these things in all my projects: I like to do these things in all my projects:
* Have all my tests run before committing. I don't like buying ice cream for the team on test failures. * Have all my tests run before committing. I don't like buying ice cream for the team on test failures.
* If I'm developing gems alongside this project, I use a `Gemfile.erb` to get around the "one gem, one source" issue in * If I'm developing gems alongside this project, I use a `Gemfile.penchant` to get around the "one gem, one source" issue in
current versions of Bundler. current versions of Bundler.
* If I'm moving to different machines or (heaven forbid!) having other developers work on the project, I want to make * If I'm moving to different machines or (heaven forbid!) having other developers work on the project, I want to make
getting all those local gems as easy as possible. getting all those local gems as easy as possible.
@ -14,27 +14,36 @@ This gem makes that easier!
Installs a bunch of scripts into the `scripts` directory of your project: Installs a bunch of scripts into the `scripts` directory of your project:
* `gemfile` which switches between `Gemfile.erb` environments * `gemfile` which switches between `Gemfile.penchant` environments
* `install-git-hooks` which will do just what it says * `install-git-hooks` which will do just what it says
* `hooks`, several git hooks that the prior script symlinks into .git/hooks for you * `hooks`, several git hooks that the prior script symlinks into .git/hooks for you
* `initialize-environment`, which bootstraps your local environment so you can get up and running * `initialize-environment`, which bootstraps your local environment so you can get up and running
## Gemfile.erb?! ## Gemfile.penchant?!
Yeah, it's a `Gemfile` with ERB in it: Yeah, it's a `Gemfile` with some extras:
``` erb ``` ruby
<% env :local do %> source :rubygems
gem 'guard', :path => '../guard'
<% end %>
<% env :remote do %> gem 'rails', '3.2.3'
gem 'guard', :git => 'git://github.com/johnbintz/guard.git' gems 'rake', 'nokogiri', 'rack-rewrite'
<% end %>
<% no_deployment do %> no_deployment do
gem 'os-specific-things' group :development, :test do
<% end %> gem 'rspec', '~> 2.6.0'
dev_gems = %w{flowerbox guard-flowerbox}
env :local do
gems dev_gems, :path => '../%s'
end
env :remote do
gems dev_gems, :git => 'git://github.com/johnbintz/%s.git'
end
end
end
``` ```
Use `script/gemfile local` to get at the local ones, and `script/gemfile remote` to get at the remote ones. Use `script/gemfile local` to get at the local ones, and `script/gemfile remote` to get at the remote ones.
@ -49,8 +58,8 @@ remote servers. *Very* helpful when you have OS-specific gems and are developing
and deploying on another, or if you don't want to deal with the dependencies for your testing and deploying on another, or if you don't want to deal with the dependencies for your testing
frameworks: frameworks:
``` erb ``` ruby
<% no_deployment do %> no_deployment do
require 'rbconfig' require 'rbconfig'
case RbConfig::CONFIG['host_os'] case RbConfig::CONFIG['host_os']
when /darwin/ when /darwin/
@ -64,7 +73,7 @@ frameworks:
group :test do group :test do
# ... all your testing libraries you won't need on the deployed end ... # ... all your testing libraries you won't need on the deployed end ...
end end
<% end %> end
``` ```
Run `penchant gemfile ENV --deployment` to get this behavior. This is run by default when the Run `penchant gemfile ENV --deployment` to get this behavior. This is run by default when the
@ -74,8 +83,8 @@ pre-commit git hook runs, but only after the default Rake task passes.
Get new developers up to speed fast! `script/initialize-environment` does the following when run: Get new developers up to speed fast! `script/initialize-environment` does the following when run:
* Check out any remote repos found in `Gemfile.erb` to the same directory where your current project lives. * Check out any remote repos found in `Gemfile.penchant` to the same directory where your current project lives.
That way, you can have your `Gemfile.erb` set up as above and everything works cleanly. That way, you can have your `Gemfile.penchant` set up as above and everything works cleanly.
* Runs `script/gemfile remote` to set your project to using remote repositories. * Runs `script/gemfile remote` to set your project to using remote repositories.
* Runs `rake bootstrap` for the project if it exists. * Runs `rake bootstrap` for the project if it exists.

View File

@ -30,7 +30,7 @@ class PenchantCLI < Thor
method_options :dir => 'script' method_options :dir => 'script'
def convert def convert
install install
FileUtils.mv 'Gemfile', 'Gemfile.erb' FileUtils.mv 'Gemfile', 'Gemfile.penchant'
gemfile(:remote) gemfile(:remote)
end end
@ -52,7 +52,7 @@ class PenchantCLI < Thor
gemfile = Penchant::Gemfile.new gemfile = Penchant::Gemfile.new
if !gemfile.has_gemfile? if !gemfile.has_gemfile?
puts "No Gemfile or Gemfile.erb, exiting." puts "No Gemfile or Gemfile.penchant, exiting."
exit 1 exit 1
end end
system %{bundle} system %{bundle}

View File

@ -49,7 +49,7 @@ Feature: Gemfiles
Scenario: Use a gem list for an operation Scenario: Use a gem list for an operation
Given I have the file "Gemfile.erb" with the content: Given I have the file "Gemfile.erb" with the content:
""" """
<% with_gem_list 'test' do %> <% gems 'test' do %>
<% env :local, :path => '../%s' do %> <% env :local, :path => '../%s' do %>
<%= gem %> <%= gem %>
<% end %> <% end %>
@ -65,7 +65,7 @@ Feature: Gemfiles
Scenario: Let gem get additional info Scenario: Let gem get additional info
Given I have the file "Gemfile.erb" with the content: Given I have the file "Gemfile.erb" with the content:
""" """
<% with_gem_list 'test' do %> <% gems 'test' do %>
<%= gem :path => '../%s' %> <%= gem :path => '../%s' %>
<% end %> <% end %>
""" """
@ -74,38 +74,24 @@ Feature: Gemfiles
""" """
# generated by penchant, environment: local # generated by penchant, environment: local
gem 'test', {:path=>"../test"}
gem 'test', :path => %{../test}
""" """
Scenario: Use a gem list without a block Scenario: Use a gem list without a block
Given I have the file "Gemfile.erb" with the content: Given I have the file "Gemfile.erb" with the content:
""" """
<% with_gem_list 'test', :path => '../%s' %> <% gems 'test', :path => '../%s' %>
""" """
When I rebuild the Gemfile for "local" mode When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content: Then the file "Gemfile" should have the following content:
""" """
# generated by penchant, environment: local # generated by penchant, environment: local
gem 'test', :path => %{../test} gem 'test', {:path=>"../test"}
""" """
Scenario: Use a gem list with an array Scenario: Use a gem list with an array
Given I have the file "Gemfile.erb" with the content:
"""
<% with_gem_list [ 'test' ], :path => '../%s' %>
"""
When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
gem 'test', :path => %{../test}
"""
Scenario: Use another gem list with an array
Given I have the file "Gemfile.erb" with the content: Given I have the file "Gemfile.erb" with the content:
""" """
<% gems [ 'test' ], :path => '../%s' %> <% gems [ 'test' ], :path => '../%s' %>
@ -114,7 +100,7 @@ Feature: Gemfiles
Then the file "Gemfile" should have the following content: Then the file "Gemfile" should have the following content:
""" """
# generated by penchant, environment: local # generated by penchant, environment: local
gem 'test', :path => %{../test} gem 'test', {:path=>"../test"}
""" """

View File

@ -49,7 +49,6 @@ Feature: Gemfiles
gem "three", {:path=>"../three"} gem "three", {:path=>"../three"}
""" """
@wip
Scenario: Use an env block Scenario: Use an env block
Given I have the file "Gemfile.penchant" with the content: Given I have the file "Gemfile.penchant" with the content:
""" """

View File

@ -74,31 +74,128 @@ module Penchant
gemfile_header['deployment mode'] != nil gemfile_header['deployment mode'] != nil
end end
class ERBFile class FileProcessor
end attr_reader :environment, :is_deployment
class PenchantFile
def self.result(data, *args) def self.result(data, *args)
new(data).result(*args) new(data).result(*args)
end end
def self.handle_result(&block)
if block
@handle_result = block
else
@handle_result
end
end
def initialize(data) def initialize(data)
@data = data @data = data
end end
attr_reader :environment, :is_deployment
def result(_env, _is_deployment) def result(_env, _is_deployment)
@environment = _env.to_s.to_sym @environment = _env.to_s.to_sym
@is_deployment = _is_deployment @is_deployment = _is_deployment
@output = [] @output = []
instance_eval(@data) handle_result(@data)
@output.join("\n") @output.join("\n")
end end
def env(*args)
yield if args.include?(environment)
end
def no_deployment
yield if !is_deployment
end
protected
def args_to_string(args)
args.inspect[1..-2]
end
def split_args(args)
template = {}
while args.last.instance_of?(Hash)
template.merge!(args.pop)
end
[ args, template ]
end
def call_and_indent_output(block)
index = @output.length
block.call
index.upto(@output.length - 1) do |i|
@output[i] = " " + @output[i]
end
end
def process_options(gem_name, template = {})
Hash[
template.collect { |key, value|
value = value % gem_name if value.respond_to?(:%)
[ key, value ]
}.sort
]
end
end
class ERBFile < FileProcessor
def handle_result(data)
@output << ERB.new(data, nil, nil, '@_erbout').result(binding)
end
def env(check, template = {}, &block)
if check.to_s == @env.to_s
original_erbout = @_erbout.dup
output = instance_eval(&block).lines.to_a
output.each do |line|
if gem_name = line[%r{gem ['"]([^'"]+)['"]}, 1]
line.replace(line.rstrip + process_options(gem_name, template) + "\n")
end
end
@_erbout = original_erbout + output.join
end
end
def gems(*gems)
template = {}
template = gems.pop if gems.last.instance_of?(Hash)
gems.flatten.each do |gem|
@_current_gem = gem
if block_given?
yield
else
@_erbout += gem(template) + "\n"
end
end
end
def gem(template = {})
output = "gem '#{@_current_gem}'"
options = process_options(@_current_gem, template)
if !options.empty?
output += ", #{options.inspect}"
end
output
end
end
class PenchantFile < FileProcessor
def handle_result(data)
instance_eval(data)
end
def gem(*args) def gem(*args)
gem_name, template = split_args(args) gem_name, template = split_args(args)
@ -135,47 +232,6 @@ module Penchant
def source(*args) def source(*args)
@output << %{source #{args_to_string(args)}} @output << %{source #{args_to_string(args)}}
end end
def env(*args)
yield if args.include?(environment)
end
def no_deployment
yield if !is_deployment
end
private
def args_to_string(args)
args.inspect[1..-2]
end
def split_args(args)
template = {}
while args.last.instance_of?(Hash)
template.merge!(args.pop)
end
[ args, template ]
end
def call_and_indent_output(block)
index = @output.length
block.call
index.upto(@output.length - 1) do |i|
@output[i] = " " + @output[i]
end
end
def process_options(gem_name, template = {})
Hash[
template.collect { |key, value|
value = value % gem_name if value.respond_to?(:%)
[ key, value ]
}.sort
]
end
end end
def switch_to!(gemfile_env = nil, deployment = false) def switch_to!(gemfile_env = nil, deployment = false)
@ -214,64 +270,20 @@ module Penchant
end end
def process(template) def process(template)
case File.extname(processable_gemfile_path) builder = case File.extname(processable_gemfile_path)
when '.penchant' when '.penchant'
PenchantFile.result(template, @env, @is_deployment) PenchantFile
when '.erb' when '.erb'
ERB.new(template, nil, nil, '@_erbout').result(binding).lines.to_a ERBFile
end end
builder.result(template, @env, @is_deployment)
end end
def template def template
File.read(processable_gemfile_path) File.read(processable_gemfile_path)
end end
def env(check, template = {}, &block)
if check.to_s == @env.to_s
original_erbout = @_erbout.dup
output = instance_eval(&block).lines.to_a
output.each do |line|
if gem_name = line[%r{gem ['"]([^'"]+)['"]}, 1]
line.replace(line.rstrip + options_to_string(gem_name, template) + "\n")
end
end
@_erbout = original_erbout + output.join
end
end
def with_gem_list(*gems)
template = {}
template = gems.pop if gems.last.instance_of?(Hash)
gems.flatten.each do |gem|
@_current_gem = gem
if block_given?
yield
else
@_erbout += gem(template) + "\n"
end
end
end
alias :gems :with_gem_list
def gem(template = {})
"gem '#{@_current_gem}'" + options_to_string(@_current_gem, template)
end
def options_to_string(gem_name, template = {})
template.collect do |key, value|
", #{key.inspect} => %{#{value % gem_name}}"
end.join
end
def no_deployment(&block)
instance_eval(&block) if !@is_deployment
end
def gemfile_header def gemfile_header
(has_gemfile? and File.readlines(gemfile_path).first) or "" (has_gemfile? and File.readlines(gemfile_path).first) or ""
end end