support pure ruby gemfile.penchant

This commit is contained in:
John Bintz 2012-06-05 07:50:33 -04:00
parent c858dcdd69
commit 47d8d3c52c
3 changed files with 310 additions and 13 deletions

View File

@ -69,3 +69,58 @@ Feature: Gemfiles
""" """
Scenario: Let gem get additional info
Given I have the file "Gemfile.erb" with the content:
"""
<% with_gem_list 'test' do %>
<%= gem :path => '../%s' %>
<% end %>
"""
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 a gem list without a block
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 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:
"""
<% gems [ '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}
"""

View File

@ -0,0 +1,120 @@
@fakefs
Feature: Gemfiles
Scenario: Process a pure Ruby gemfile
Given I have the file "Gemfile.penchant" with the content:
"""
source :rubygems
group :cats, :dogs do
case environment
when :local
gem 'test', :path => '../test'
when :remote
gem 'test', :git => 'git://github.com/johnbintz/test.git'
end
end
"""
When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
source :rubygems
group :cats, :dogs do
gem "test", {:path=>"../test"}
end
"""
When I rebuild the Gemfile for "remote" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: remote
source :rubygems
group :cats, :dogs do
gem "test", {:git=>"git://github.com/johnbintz/test.git"}
end
"""
Scenario: Use a gemlist
Given I have the file "Gemfile.penchant" with the content:
"""
gems 'one', 'two', 'three', :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 "one", {:path=>"../one"}
gem "two", {:path=>"../two"}
gem "three", {:path=>"../three"}
"""
Scenario: Use an env block
Given I have the file "Gemfile.penchant" with the content:
"""
env :local do
gems 'one', 'two', 'three', :path => '../%s'
end
"""
When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
gem "one", {:path=>"../one"}
gem "two", {:path=>"../two"}
gem "three", {:path=>"../three"}
"""
When I rebuild the Gemfile for "remote" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: remote
"""
Scenario: Skip deployment blocks
Given I have the file "Gemfile.penchant" with the content:
"""
no_deployment do
gem 'one'
end
"""
When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
gem "one"
"""
When I rebuild the Gemfile for "local" mode with deployment
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local, deployment mode (was local)
"""
Scenario: Peel multiple hashes off a gemlist
Given I have the file "Gemfile.penchant" with the content:
"""
gems 'one', { :path => '../%s' }, { :require => nil }
"""
When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
gem "one", {:path=>"../one", :require=>nil}
"""
@wip
Scenario: Don't add an empty hash
Given I have the file "Gemfile.penchant" with the content:
"""
gems 'one'
"""
When I rebuild the Gemfile for "local" mode
Then the file "Gemfile" should have the following content:
"""
# generated by penchant, environment: local
gem "one"
"""

View File

@ -18,7 +18,7 @@ module Penchant
def self.pre_switch(env, deployment = false) def self.pre_switch(env, deployment = false)
gemfile = Penchant::Gemfile.new gemfile = Penchant::Gemfile.new
return false if !gemfile.has_gemfile_erb? return false if !gemfile.has_processable_gemfile?
gemfile.run_dot_penchant!(env, deployment) gemfile.run_dot_penchant!(env, deployment)
gemfile gemfile
@ -46,10 +46,26 @@ module Penchant
file_in_path('Gemfile.erb') file_in_path('Gemfile.erb')
end end
def gemfile_penchant_path
file_in_path('Gemfile.penchant')
end
def has_gemfile_erb? def has_gemfile_erb?
File.file?(gemfile_erb_path) File.file?(gemfile_erb_path)
end end
def has_gemfile_penchant?
File.file?(gemfile_penchant_path)
end
def has_processable_gemfile?
has_gemfile_erb? || has_gemfile_penchant?
end
def processable_gemfile_path
has_gemfile_erb? ? gemfile_erb_path : gemfile_penchant_path
end
def environment def environment
gemfile_header.strip[%r{environment: ([^, ]*)}, 1] gemfile_header.strip[%r{environment: ([^, ]*)}, 1]
end end
@ -58,10 +74,97 @@ module Penchant
gemfile_header['deployment mode'] != nil gemfile_header['deployment mode'] != nil
end end
class ERBFile
end
class PenchantFile
def self.result(data, *args)
new(data).result(*args)
end
def initialize(data)
@data = data
end
attr_reader :environment, :is_deployment
def result(_env, _is_deployment)
@environment = _env.to_s.to_sym
@is_deployment = _is_deployment
@output = []
instance_eval(@data)
@output.join("\n")
end
def gem(*args)
@output << %{gem #{args_to_string(args)}}
end
def gems(*gems)
template = {}
while gems.last.instance_of?(Hash)
template.merge!(gems.pop)
end
gems.flatten.each do |gem_name|
options = Hash[
template.collect { |key, value|
value = value % gem_name if value.respond_to?(:%)
[ key, value ]
}.sort
]
args = [ gem_name ]
args << options if !options.empty?
gem *args
end
end
def group(*args, &block)
@output << ""
@output << %{group #{args_to_string(args)} do}
call_and_indent_output(block)
@output << %{end}
end
def source(*args)
@output << %{source #{args_to_string(args)}}
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 call_and_indent_output(block)
index = @output.length
block.call
index.upto(@output.length - 1) do |i|
@output[i] = " " + @output[i]
end
end
end
def switch_to!(gemfile_env = nil, deployment = false) def switch_to!(gemfile_env = nil, deployment = false)
@env, @is_deployment = gemfile_env, deployment @env, @is_deployment = gemfile_env, deployment
output = [ header, ERB.new(template, nil, nil, '@_erbout').result(binding) ] output = [ header, process(template) ]
File.open(gemfile_path, 'wb') { |fh| fh.print output.join("\n") } File.open(gemfile_path, 'wb') { |fh| fh.print output.join("\n") }
end end
@ -93,8 +196,17 @@ module Penchant
File.join(@path, file) File.join(@path, file)
end end
def process(template)
case File.extname(processable_gemfile_path)
when '.penchant'
PenchantFile.result(template, @env, @is_deployment)
when '.erb'
ERB.new(template, nil, nil, '@_erbout').result(binding).lines.to_a
end
end
def template def template
File.read(gemfile_erb_path) File.read(processable_gemfile_path)
end end
def env(check, template = {}, &block) def env(check, template = {}, &block)
@ -105,12 +217,7 @@ module Penchant
output.each do |line| output.each do |line|
if gem_name = line[%r{gem ['"]([^'"]+)['"]}, 1] if gem_name = line[%r{gem ['"]([^'"]+)['"]}, 1]
new_line = line.rstrip line.replace(line.rstrip + options_to_string(gem_name, template) + "\n")
template.each do |key, value|
new_line += ", #{key.inspect} => %{#{value % gem_name}}"
end
new_line += "\n"
line.replace(new_line)
end end
end end
@ -119,14 +226,29 @@ module Penchant
end end
def with_gem_list(*gems) def with_gem_list(*gems)
gems.each do |gem| template = {}
template = gems.pop if gems.last.instance_of?(Hash)
gems.flatten.each do |gem|
@_current_gem = gem @_current_gem = gem
yield if block_given?
yield
else
@_erbout += gem(template) + "\n"
end
end end
end end
def gem alias :gems :with_gem_list
"gem '#{@_current_gem}'"
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 end
def no_deployment(&block) def no_deployment(&block)