penchant 0.2.24 → 0.2.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -32,6 +32,9 @@ source :rubygems
32
32
  # ensure git hooks are installed when a gemfile is processed, see below
33
33
  ensure_git_hooks!
34
34
 
35
+ # deploying to heroku and want 1.9.3 goodness?
36
+ ruby '1.9.3'
37
+
35
38
  gem 'rails', '3.2.3'
36
39
  # expands to:
37
40
  #
data/Rakefile CHANGED
@@ -1,22 +1,6 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
- begin
5
- require 'rspec/core/rake_task'
6
-
7
- RSpec::Core::RakeTask.new(:spec)
8
- rescue LoadError
9
- "#$! - no rspec"
10
- end
11
-
12
- begin
13
- require 'rspec/core/rake_task'
14
-
15
- RSpec::Core::RakeTask.new(:spec)
16
- rescue LoadError
17
- "#$! - no rspec"
18
- end
19
-
20
4
  begin
21
5
  require 'cucumber'
22
6
  require 'cucumber/rake/task'
@@ -28,5 +12,5 @@ rescue LoadError
28
12
  "#$! - no cucumber"
29
13
  end
30
14
 
31
- task :default => [ :spec, :cucumber ]
15
+ task :default => [ :cucumber ]
32
16
 
data/features/cli.feature CHANGED
@@ -1,6 +1,6 @@
1
1
  Feature: CLI
2
2
  Scenario: Switch back to the original pre-deployment environment
3
- Given I have the file "tmp/Gemfile.erb" with the content:
3
+ Given I have the file "tmp/Gemfile.penchant" with the content:
4
4
  """
5
5
  gem 'rake'
6
6
  """
@@ -12,7 +12,7 @@ Feature: CLI
12
12
  Then the file "tmp/Gemfile" should have the following content:
13
13
  """
14
14
  # generated by penchant, environment: local
15
- gem 'rake'
15
+ gem "rake"
16
16
  """
17
17
  And the output should include "fallback: other"
18
18
 
@@ -263,6 +263,7 @@ Feature: Gemfiles
263
263
  gem "two", {:require=>nil}
264
264
  """
265
265
 
266
+ @wip
266
267
  Scenario: Set the opposite environment in the environment defaults
267
268
  Given I have the file "Gemfile.penchant" with the content:
268
269
  """
@@ -411,3 +412,14 @@ Feature: Gemfiles
411
412
  gem "one"
412
413
  """
413
414
 
415
+ Scenario: Pass through the Ruby version
416
+ Given I have the file "Gemfile.penchant" with the content:
417
+ """
418
+ ruby '1.9.3'
419
+ """
420
+ When I rebuild the Gemfile for "local" mode
421
+ Then the file "Gemfile" should have the following content:
422
+ """
423
+ # generated by penchant, environment: local
424
+ ruby "1.9.3"
425
+ """
@@ -1,3 +1,3 @@
1
1
  Given /^I am on the "([^"]*)" platform$/ do |os|
2
- Penchant::Gemfile::PenchantFile.any_instance.stubs(:current_os).returns(os.to_sym)
2
+ Penchant::FileProcessor.any_instance.stubs(:current_os).returns(os.to_sym)
3
3
  end
@@ -0,0 +1,20 @@
1
+ module Penchant
2
+ class CustomProperty
3
+ def initialize(value)
4
+ @value = value
5
+ end
6
+
7
+ def process(values)
8
+ if @value.respond_to?(:call)
9
+ @value.call(*values).to_a
10
+ else
11
+ @value.collect do |k, v|
12
+ v = v.dup.gsub(%r{\$(\d+)}) { |m| values[m.to_i - 1 ] }
13
+
14
+ [ k, v ]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,11 @@
1
+ module Penchant
2
+ class Defaults
3
+ def initialize
4
+ @defaults = {}
5
+ end
6
+
7
+ def [](key)
8
+ @defaults[key.to_s] ||= {}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Penchant
2
+ class Env
3
+ attr_accessor :name
4
+
5
+ def initialize(name)
6
+ @name = name.to_s
7
+ end
8
+
9
+ def ==(other)
10
+ @name == other.name
11
+ end
12
+
13
+ def to_s
14
+ "@#{name}"
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,201 @@
1
+ module Penchant
2
+ class FileProcessor
3
+ attr_reader :environment, :is_deployment, :available_environments, :defined_git_repos
4
+
5
+ ANY_ENVIRONMENT = :any_environment
6
+
7
+ def self.result(data, *args)
8
+ new(data).result(*args)
9
+ end
10
+
11
+ def initialize(data)
12
+ @data = data
13
+ @available_environments = []
14
+ @defined_git_repos = []
15
+ @defaults = Defaults.new
16
+ @properties = PropertyStackBuilder.new(@defaults)
17
+
18
+ @_current_env_defaults = {}
19
+ end
20
+
21
+ def result(_env, _is_deployment)
22
+ @environment = _env.to_s.to_sym
23
+ @is_deployment = _is_deployment
24
+
25
+ @output = []
26
+
27
+ instance_eval(@data)
28
+
29
+ @output.join("\n")
30
+ end
31
+
32
+ def <<(string)
33
+ @output << string
34
+ end
35
+
36
+ def env(*args)
37
+ options = {}
38
+ options = args.pop if args.last.kind_of?(::Hash)
39
+
40
+ @available_environments += args
41
+
42
+ requested_env_defaults = _defaults_for(Env.new(environment))
43
+
44
+ if block_given?
45
+ if for_environment?(args)
46
+ @_current_env_defaults = requested_env_defaults
47
+ yield
48
+ @_current_env_defaults = {}
49
+ else
50
+ if opposite_environment = (options[:opposite] or requested_env_defaults[:opposite])
51
+ if for_environment?([ environment, args, opposite_environment ].flatten.uniq)
52
+ @_current_env_defaults = requested_env_defaults
53
+ @_strip_pathing_options = true
54
+ yield
55
+ @_strip_pathing_options = false
56
+ @_current_env_defaults = {}
57
+ end
58
+ end
59
+ end
60
+ else
61
+ Env.new(args.shift)
62
+ end
63
+ end
64
+
65
+ def property(name, hash = nil, &block)
66
+ @properties[name] = hash || block
67
+ end
68
+
69
+ def opposites(left, right)
70
+ @defaults[Env.new(left)][:opposite] = right
71
+ @defaults[Env.new(right)][:opposite] = left
72
+ end
73
+
74
+ def for_environment?(envs)
75
+ envs.include?(environment) || environment == ANY_ENVIRONMENT
76
+ end
77
+
78
+ def no_deployment
79
+ yield if !is_deployment
80
+ end
81
+
82
+ def ensure_git_hooks!
83
+ Penchant::Hooks.install!
84
+ end
85
+
86
+ def os(*args)
87
+ yield if args.include?(current_os)
88
+ end
89
+
90
+ def defaults_for(*args)
91
+ defaults = args.pop
92
+
93
+ args.flatten.each do |gem|
94
+ @defaults[gem].merge!(defaults)
95
+ end
96
+ end
97
+
98
+ protected
99
+ def args_to_string(args)
100
+ args.inspect[1..-2]
101
+ end
102
+
103
+ def split_args(args)
104
+ template = {}
105
+
106
+ while args.last.instance_of?(Hash)
107
+ template.merge!(args.pop)
108
+ end
109
+
110
+ [ args, template ]
111
+ end
112
+
113
+ def call_and_indent_output(block = nil, &given_block)
114
+ index = @output.length
115
+ (block || given_block).call
116
+ index.upto(@output.length - 1) do |i|
117
+ @output[i] = " " + @output[i]
118
+ end
119
+ end
120
+
121
+ def _defaults_for(gem_name)
122
+ result = @_current_env_defaults
123
+ result.merge(@defaults[gem_name] || {})
124
+ end
125
+
126
+ def current_os
127
+ require 'rbconfig'
128
+ case host_os = RbConfig::CONFIG['host_os']
129
+ when /darwin/
130
+ :darwin
131
+ when /linux/
132
+ :linux
133
+ else
134
+ host_os[%r{^[a-z]+}, 1].to_sym
135
+ end
136
+ end
137
+
138
+ def gem(*args)
139
+ gem_name = [ args.shift ]
140
+ template = {}
141
+
142
+ if args.last.kind_of?(::Hash)
143
+ template = args.pop
144
+ end
145
+
146
+ version = args.first
147
+
148
+ options = @properties.create_stack_for(template, @_strip_pathing_options).process_for_gem(gem_name.first, @_current_env_defaults)
149
+
150
+ args = [ gem_name.first ]
151
+ args << version if version
152
+
153
+ if options[:git]
154
+ @defined_git_repos << Penchant::Repo.new(options[:git])
155
+ end
156
+
157
+ args << options if !options.empty?
158
+
159
+ self << %{gem #{args_to_string(args)}}
160
+ end
161
+
162
+ def gems(*args)
163
+ gems, template = split_args(args)
164
+
165
+ gems.flatten.each do |gem_name|
166
+ options = @properties.create_stack_for(template, @_strip_pathing_options).process_for_gem(gem_name)
167
+
168
+ args = [ gem_name ]
169
+ args << options if !options.empty?
170
+
171
+ gem *args
172
+ end
173
+ end
174
+
175
+ def group(*args, &block)
176
+ self << ""
177
+ self << %{group #{args_to_string(args)} do}
178
+
179
+ call_and_indent_output(block)
180
+
181
+ self << %{end}
182
+ end
183
+
184
+ def ruby(*args)
185
+ passthrough :ruby, *args
186
+ end
187
+
188
+ def gemspec
189
+ passthrough :gemspec
190
+ end
191
+
192
+ def source(*args)
193
+ passthrough :source, *args
194
+ end
195
+
196
+ def passthrough(method, *args)
197
+ self << %{#{method} #{args_to_string(args)}}.strip
198
+ end
199
+ end
200
+ end
201
+
@@ -1,5 +1,3 @@
1
- require 'erb'
2
-
3
1
  module Penchant
4
2
  class Gemfile
5
3
  attr_reader :path, :is_deployment
@@ -51,28 +49,20 @@ module Penchant
51
49
  File.file?('.penchant')
52
50
  end
53
51
 
54
- def gemfile_erb_path
55
- file_in_path('Gemfile.erb')
56
- end
57
-
58
52
  def gemfile_penchant_path
59
53
  file_in_path('Gemfile.penchant')
60
54
  end
61
55
 
62
- def has_gemfile_erb?
63
- File.file?(gemfile_erb_path)
64
- end
65
-
66
56
  def has_gemfile_penchant?
67
57
  File.file?(gemfile_penchant_path)
68
58
  end
69
59
 
70
60
  def has_processable_gemfile?
71
- has_gemfile_erb? || has_gemfile_penchant?
61
+ has_gemfile_penchant?
72
62
  end
73
63
 
74
64
  def processable_gemfile_path
75
- has_gemfile_erb? ? gemfile_erb_path : gemfile_penchant_path
65
+ gemfile_penchant_path
76
66
  end
77
67
 
78
68
  def environment
@@ -83,329 +73,6 @@ module Penchant
83
73
  gemfile_header['deployment mode'] != nil
84
74
  end
85
75
 
86
- class Env
87
- attr_accessor :name
88
-
89
- def initialize(name)
90
- @name = name.to_s
91
- end
92
-
93
- def ==(other)
94
- @name == other.name
95
- end
96
-
97
- def to_s
98
- "@#{name}"
99
- end
100
- end
101
-
102
- class FileProcessor
103
- attr_reader :environment, :is_deployment, :available_environments, :defined_git_repos
104
-
105
- ANY_ENVIRONMENT = :any_environment
106
-
107
- def self.result(data, *args)
108
- new(data).result(*args)
109
- end
110
-
111
- def self.handle_result(&block)
112
- if block
113
- @handle_result = block
114
- else
115
- @handle_result
116
- end
117
- end
118
-
119
- def initialize(data)
120
- @data = data
121
- @available_environments = []
122
- @defined_git_repos = []
123
- @defaults = {}
124
- @properties = {}
125
-
126
- @_current_env_defaults = {}
127
- end
128
-
129
- def result(_env, _is_deployment)
130
- @environment = _env.to_s.to_sym
131
- @is_deployment = _is_deployment
132
-
133
- @output = []
134
-
135
- handle_result(@data)
136
-
137
- @output.join("\n")
138
- end
139
-
140
- def env(*args)
141
- options = {}
142
- options = args.pop if args.last.kind_of?(::Hash)
143
-
144
- @available_environments += args
145
-
146
- requested_env_defaults = _defaults_for(Env.new(environment))
147
-
148
- if block_given?
149
- if for_environment?(args)
150
- @_current_env_defaults = requested_env_defaults
151
- yield
152
- @_current_env_defaults = {}
153
- else
154
- if opposite_environment = (options[:opposite] or requested_env_defaults[:opposite])
155
- if for_environment?([ environment, args, opposite_environment ].flatten.uniq)
156
- @_current_env_defaults = requested_env_defaults
157
- @_strip_pathing_options = true
158
- yield
159
- @_strip_pathing_options = false
160
- @_current_env_defaults = {}
161
- end
162
- end
163
- end
164
- else
165
- Env.new(args.shift)
166
- end
167
- end
168
-
169
- def property(name, hash = nil, &block)
170
- @properties[name] = hash || block
171
- end
172
-
173
- def opposites(left, right)
174
- @defaults[Env.new(left).to_s] ||= {}
175
- @defaults[Env.new(left).to_s][:opposite] = right
176
-
177
- @defaults[Env.new(right).to_s] ||= {}
178
- @defaults[Env.new(right).to_s][:opposite] = left
179
- end
180
-
181
- def for_environment?(envs)
182
- envs.include?(environment) || environment == ANY_ENVIRONMENT
183
- end
184
-
185
- def no_deployment
186
- yield if !is_deployment
187
- end
188
-
189
- def ensure_git_hooks!
190
- Penchant::Hooks.install!
191
- end
192
-
193
- def os(*args)
194
- yield if args.include?(current_os)
195
- end
196
-
197
- def defaults_for(*args)
198
- defaults = args.pop
199
-
200
- args.flatten.each do |gem|
201
- @defaults[gem.to_s] ||= {}
202
- @defaults[gem.to_s].merge!(defaults)
203
- end
204
- end
205
-
206
- protected
207
- def args_to_string(args)
208
- args.inspect[1..-2]
209
- end
210
-
211
- def split_args(args)
212
- template = {}
213
-
214
- while args.last.instance_of?(Hash)
215
- template.merge!(args.pop)
216
- end
217
-
218
- [ args, template ]
219
- end
220
-
221
- def call_and_indent_output(block)
222
- index = @output.length
223
- block.call
224
- index.upto(@output.length - 1) do |i|
225
- @output[i] = " " + @output[i]
226
- end
227
- end
228
-
229
- def process_options(gem_name, template = {})
230
- properties = {}
231
-
232
- property_stack = template.to_a
233
-
234
- original_properties = process_option_stack(gem_name, property_stack)
235
-
236
- if @_strip_pathing_options
237
- [ :git, :branch, :path ].each { |key| original_properties.delete(key) }
238
- end
239
-
240
- properties = process_option_stack(gem_name, _defaults_for(gem_name).to_a).merge(original_properties)
241
-
242
- properties.delete(:opposite)
243
-
244
- Hash[properties.sort]
245
- end
246
-
247
- def process_option_stack(gem_name, stack)
248
- property_stack = stack.dup
249
- properties = {}
250
-
251
- while !property_stack.empty?
252
- key, value = property_stack.shift
253
-
254
- if property = @properties[key]
255
- values = [ value ].flatten
256
-
257
- if property.respond_to?(:call)
258
- property.call(*values).each do |k, v|
259
- property_stack.push([ k, v ])
260
- end
261
- else
262
- property.each do |k, v|
263
- v = v.dup.gsub(%r{\$(\d+)}) { |m| values[m.to_i - 1 ] }
264
- property_stack.push([ k, v ])
265
- end
266
- end
267
- else
268
- value = value % gem_name if value.respond_to?(:%)
269
-
270
- properties[key] = value
271
- end
272
- end
273
-
274
- properties
275
- end
276
-
277
- def _defaults_for(gem_name)
278
- result = @_current_env_defaults
279
- result.merge(@defaults[gem_name.to_s] || {})
280
- end
281
-
282
- def current_os
283
- require 'rbconfig'
284
- case host_os = RbConfig::CONFIG['host_os']
285
- when /darwin/
286
- :darwin
287
- when /linux/
288
- :linux
289
- else
290
- host_os[%r{^[a-z]+}, 1].to_sym
291
- end
292
- end
293
- end
294
-
295
- class ERBFile < FileProcessor
296
- def handle_result(data)
297
- $stderr.puts "ERB files are deprecated. Please convert them to the Ruby format."
298
-
299
- @output << ERB.new(data, nil, nil, '@_erbout').result(binding)
300
- end
301
-
302
- def env(check, template = {}, &block)
303
- if check.to_s == @environment.to_s
304
- original_erbout = @_erbout.dup
305
- @_erbout = ''
306
-
307
- output = instance_eval(&block).lines.to_a
308
-
309
- output.each do |line|
310
- if gem_name = line[%r{gem ['"]([^'"]+)['"]}, 1]
311
- new_line = line.rstrip
312
-
313
- if !(options = process_options(gem_name, template)).empty?
314
- new_line += ", #{options.inspect}"
315
- end
316
-
317
- line.replace(new_line + "\n")
318
- end
319
- end
320
-
321
- @_erbout = original_erbout + output.join
322
- end
323
- end
324
-
325
- def gems(*gems)
326
- template = {}
327
- template = gems.pop if gems.last.instance_of?(Hash)
328
-
329
- gems.flatten.each do |gem|
330
- @_current_gem = gem
331
- if block_given?
332
- yield
333
- else
334
- @_erbout += gem(template) + "\n"
335
- end
336
- end
337
- end
338
-
339
- def gem(template = {})
340
- output = "gem '#{@_current_gem}'"
341
- options = process_options(@_current_gem, template)
342
- if !options.empty?
343
- output += ", #{options.inspect}"
344
- end
345
- output
346
- end
347
- end
348
-
349
- class PenchantFile < FileProcessor
350
- def handle_result(data)
351
- instance_eval(data)
352
- end
353
-
354
- def gem(*args)
355
- gem_name = [ args.shift ]
356
- template = {}
357
-
358
- if args.last.kind_of?(::Hash)
359
- template = args.pop
360
- end
361
-
362
- version = args.first
363
-
364
- options = process_options(gem_name.first, template)
365
-
366
- args = [ gem_name.first ]
367
- args << version if version
368
-
369
- if options[:git]
370
- @defined_git_repos << Penchant::Repo.new(options[:git])
371
- end
372
-
373
- args << options if !options.empty?
374
-
375
- @output << %{gem #{args_to_string(args)}}
376
- end
377
-
378
- def gemspec
379
- @output << %{gemspec}
380
- end
381
-
382
- def gems(*args)
383
- gems, template = split_args(args)
384
-
385
- gems.flatten.each do |gem_name|
386
- options = process_options(gem_name, template)
387
-
388
- args = [ gem_name ]
389
- args << options if !options.empty?
390
-
391
- gem *args
392
- end
393
- end
394
-
395
- def group(*args, &block)
396
- @output << ""
397
- @output << %{group #{args_to_string(args)} do}
398
-
399
- call_and_indent_output(block)
400
-
401
- @output << %{end}
402
- end
403
-
404
- def source(*args)
405
- @output << %{source #{args_to_string(args)}}
406
- end
407
- end
408
-
409
76
  def available_environments
410
77
  process
411
78
  builder.available_environments
@@ -456,16 +123,7 @@ module Penchant
456
123
  end
457
124
 
458
125
  def builder
459
- return @builder if @builder
460
-
461
- klass = case File.extname(processable_gemfile_path)
462
- when '.penchant'
463
- PenchantFile
464
- when '.erb'
465
- ERBFile
466
- end
467
-
468
- @builder = klass.new(template)
126
+ @builder ||= FileProcessor.new(template)
469
127
  end
470
128
 
471
129
  def template