courtier 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +63 -0
- data/.yardopts +8 -0
- data/Config.rb +82 -0
- data/HISTORY.md +20 -0
- data/LICENSE.txt +27 -0
- data/NOTES.md +38 -0
- data/README.md +185 -0
- data/lib/c.rb +7 -0
- data/lib/courtier.rb +8 -0
- data/lib/courtier/config.rb +249 -0
- data/lib/courtier/config_filter.rb +104 -0
- data/lib/courtier/configuration.rb +335 -0
- data/lib/courtier/core_ext.rb +78 -0
- data/lib/courtier/interface.rb +353 -0
- data/lib/courtier/properties.rb +44 -0
- data/lib/courtier/setup.rb +46 -0
- data/lib/courtier/tweaks/rake.rb +31 -0
- data/lib/rc.rb +2 -0
- data/spec/00_concept.md +23 -0
- data/spec/01_config.md +14 -0
- data/spec/02_configuration.md +51 -0
- data/spec/03_import.md +49 -0
- data/spec/06_interface.md +39 -0
- data/spec/applique/ae.rb +1 -0
- data/spec/applique/file.rb +8 -0
- data/spec/applique/fixture.rb +10 -0
- data/spec/applique/fixture/config.rb +16 -0
- data/spec/cov.rb +7 -0
- metadata +135 -0
@@ -0,0 +1,249 @@
|
|
1
|
+
module Courtier
|
2
|
+
|
3
|
+
# Config encapsulates a single configuration entry as defined
|
4
|
+
# in a project's configuration file.
|
5
|
+
#
|
6
|
+
class Config
|
7
|
+
|
8
|
+
#
|
9
|
+
# Initialize Config instance. Config instances are per-configuration,
|
10
|
+
# which means they are associated with one and only one config entry.
|
11
|
+
#
|
12
|
+
# @param [#to_sym] tool
|
13
|
+
# The tool's name.
|
14
|
+
#
|
15
|
+
# @param [#to_sym,nil] profile
|
16
|
+
# Profile name, or +nil+.
|
17
|
+
#
|
18
|
+
# @param [Hash] properties
|
19
|
+
# Any additional properties associated with the config entry.
|
20
|
+
#
|
21
|
+
def initialize(tool, properties={}, &block)
|
22
|
+
@property = {:profile=>'default'}
|
23
|
+
|
24
|
+
@property[:command] = tool.to_s
|
25
|
+
@property[:feature] = tool.to_s
|
26
|
+
|
27
|
+
@block = block
|
28
|
+
|
29
|
+
properties.each do |k, v|
|
30
|
+
property(k,v)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Get/set property.
|
36
|
+
#
|
37
|
+
def property(name, value=ArgumentError)
|
38
|
+
name = name.to_sym
|
39
|
+
|
40
|
+
return @property[name] if value == ArgumentError
|
41
|
+
|
42
|
+
case name
|
43
|
+
when :feature, :command, :profile
|
44
|
+
@property[name] = value.to_s
|
45
|
+
else
|
46
|
+
@property[name] = value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# The feature being configured.
|
52
|
+
#
|
53
|
+
def feature
|
54
|
+
@property[:feature]
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# The name of command being configured.
|
59
|
+
#
|
60
|
+
def command
|
61
|
+
@property[:command]
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# @todo Deprecate?
|
66
|
+
#
|
67
|
+
alias :tool :command
|
68
|
+
|
69
|
+
#
|
70
|
+
# The name of the profile to which this configuration belongs.
|
71
|
+
#
|
72
|
+
def profile
|
73
|
+
@property[:profile]
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# The library from which this configuration derives.
|
78
|
+
# This is a shortcut for `property(:from)`.
|
79
|
+
#
|
80
|
+
def from
|
81
|
+
@property[:from]
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
#
|
86
|
+
#
|
87
|
+
def onload?
|
88
|
+
@property[:onload]
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Most configuration are scripted. In thos cases the
|
93
|
+
# `@block` attributes holds the Proc instance, otherwise
|
94
|
+
# it is `nil`.
|
95
|
+
#
|
96
|
+
attr :block
|
97
|
+
|
98
|
+
#
|
99
|
+
# IDEA: Presets would be processed first and not require the underlying feature.
|
100
|
+
#
|
101
|
+
#def preset?
|
102
|
+
# @property[:preset]
|
103
|
+
#end
|
104
|
+
|
105
|
+
#
|
106
|
+
# The arity of the configuration procedure.
|
107
|
+
#
|
108
|
+
# @return [Fixnum] number of arguments
|
109
|
+
#
|
110
|
+
def arity
|
111
|
+
@block ? @block.arity : 0
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Require the feature.
|
116
|
+
#
|
117
|
+
def require_feature
|
118
|
+
begin
|
119
|
+
require feature
|
120
|
+
rescue LoadError
|
121
|
+
#warn "No such feature -- `#{feature}'"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# Call the configuration procedure.
|
127
|
+
#
|
128
|
+
def call(*args)
|
129
|
+
block.call(*args) if block
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Returns underlying block.
|
134
|
+
#
|
135
|
+
def to_proc
|
136
|
+
block
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
## Convert block into a Hash.
|
141
|
+
##
|
142
|
+
## @return [Hash]
|
143
|
+
##
|
144
|
+
#def to_h
|
145
|
+
# HashBuilder.new(&self)).to_h
|
146
|
+
#end
|
147
|
+
|
148
|
+
#
|
149
|
+
# Copy the configuration with alterations.
|
150
|
+
#
|
151
|
+
# @param [Hash] alt
|
152
|
+
# Alternate values for configuration attributes.
|
153
|
+
#
|
154
|
+
# @return [Config] copied config
|
155
|
+
#
|
156
|
+
def copy(alt={})
|
157
|
+
tool = @property[:feature] || @property[:command]
|
158
|
+
copy = self.class.new(tool, @property.dup, &@block)
|
159
|
+
alt.each do |k,v|
|
160
|
+
copy.property(k, v)
|
161
|
+
end
|
162
|
+
copy
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Match config against tool and/or profile names.
|
167
|
+
#
|
168
|
+
# @return [Boolean]
|
169
|
+
#
|
170
|
+
def match?(*args)
|
171
|
+
props = Hash === args.last ? args.pop : {}
|
172
|
+
|
173
|
+
if tool = args.shift
|
174
|
+
props[:command] = tool.to_s
|
175
|
+
props[:feature] = tool.to_s
|
176
|
+
end
|
177
|
+
|
178
|
+
if props[:profile]
|
179
|
+
props[:profile] = (props[:profile] || :default).to_s
|
180
|
+
end
|
181
|
+
|
182
|
+
props.each do |k,v|
|
183
|
+
return false unless property(k) == v
|
184
|
+
end
|
185
|
+
|
186
|
+
return true
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# Does the given `feature` match the config's feature?
|
191
|
+
#
|
192
|
+
# @return [Boolean]
|
193
|
+
#
|
194
|
+
def feature?(feature=Courtier.current_feature)
|
195
|
+
self.feature == feature.to_s
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Does the given `command` match the config's command?
|
200
|
+
#
|
201
|
+
# @return [Boolean]
|
202
|
+
#
|
203
|
+
def command?(command=Courtier.current_command)
|
204
|
+
self.command == command.to_s
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# Does the given `profile` match the config's profile?
|
209
|
+
#
|
210
|
+
# @return [Boolean]
|
211
|
+
#
|
212
|
+
def profile?(profile=Courtier.current_profile)
|
213
|
+
self.profile == (profile || :default).to_s
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# @todo The feature argument might not be needed.
|
218
|
+
#
|
219
|
+
#def configure(feature)
|
220
|
+
# return false if self.feature != feature
|
221
|
+
#
|
222
|
+
# if setup = Courtier.setup(feature)
|
223
|
+
# setup.call(self)
|
224
|
+
# else
|
225
|
+
# block.call if command?
|
226
|
+
# end
|
227
|
+
#end
|
228
|
+
|
229
|
+
##
|
230
|
+
## Ruby 1.9 defines #inspect as #to_s, ugh.
|
231
|
+
##
|
232
|
+
#def inspect
|
233
|
+
# "#<#{self.class.name}:#{object_id} @tool=%s @profile=%s>" % [tool.inspect, profile.inspect]
|
234
|
+
#end
|
235
|
+
|
236
|
+
#
|
237
|
+
# Does the configuration apply?
|
238
|
+
#
|
239
|
+
# @return [Boolean]
|
240
|
+
#
|
241
|
+
def apply?()
|
242
|
+
return false unless command? if command
|
243
|
+
return false unless profile? if profile
|
244
|
+
return true
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Courtier
|
2
|
+
|
3
|
+
#
|
4
|
+
class ConfigFilter
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
#
|
8
|
+
# Initialize new ConfigFilter.
|
9
|
+
#
|
10
|
+
# @param [Array<Config>] List if Config instances.
|
11
|
+
#
|
12
|
+
def initialize(configuration, criteria={})
|
13
|
+
@configuration = configuration
|
14
|
+
@criteria = criteria
|
15
|
+
|
16
|
+
@list = []
|
17
|
+
|
18
|
+
configuration.each do |c|
|
19
|
+
@list << c if c.match?(criteria)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
def tool
|
27
|
+
@criteria[:tool]
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
#
|
32
|
+
#
|
33
|
+
def profile
|
34
|
+
@criteria[:profile]
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Returns list of profiles.
|
39
|
+
#
|
40
|
+
def profiles
|
41
|
+
@list.map{ |c| c.profile }
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
#
|
46
|
+
#
|
47
|
+
def [](subset)
|
48
|
+
return method_missing(:[]) if profile
|
49
|
+
if tool
|
50
|
+
criteria = @criteria.dup
|
51
|
+
criteria[:profile] = subset
|
52
|
+
else
|
53
|
+
criteria = @criteria.dup
|
54
|
+
criteria[:tool] = subset
|
55
|
+
end
|
56
|
+
self.class.new(@configuration, criteria)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
#
|
61
|
+
#
|
62
|
+
def each(&block)
|
63
|
+
@list.each do
|
64
|
+
block
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
#
|
70
|
+
#
|
71
|
+
def size
|
72
|
+
@list.size
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Call each config.
|
77
|
+
#
|
78
|
+
def call(*args)
|
79
|
+
@list.each do |c|
|
80
|
+
if c.profile?(RC.current_profile)
|
81
|
+
c.call(*args)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Convert to Proc.
|
88
|
+
#
|
89
|
+
def to_proc(exec=false)
|
90
|
+
list = @list
|
91
|
+
if exec
|
92
|
+
Proc.new do |*args|
|
93
|
+
list.each{ |c| instance_exec(*args, &c) }
|
94
|
+
end
|
95
|
+
else
|
96
|
+
Proc.new do |*args|
|
97
|
+
list.each{ |c| c.call(*args) }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,335 @@
|
|
1
|
+
module Courtier
|
2
|
+
|
3
|
+
# The Configuration class encapsulates a project/library's tool
|
4
|
+
# configuration.
|
5
|
+
#
|
6
|
+
class Configuration < Module
|
7
|
+
|
8
|
+
#
|
9
|
+
# Configuration is Enumerable.
|
10
|
+
#
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
#
|
14
|
+
# Configuration file pattern. The standard configuration file name is
|
15
|
+
# `Config.rb`, and that name should be used in most cases. However,
|
16
|
+
# `.config.rb` can also be use and will take precedence if found.
|
17
|
+
# Conversely, `config.rb` (lowercase form) can also be used but has
|
18
|
+
# the least precedence.
|
19
|
+
#
|
20
|
+
# Config files looked for in the order or precedence:
|
21
|
+
#
|
22
|
+
# * `.config.rb` or `.confile.rb`
|
23
|
+
# * `Config.rb` or `Confile.rb`
|
24
|
+
# * `config.rb` or `confile.rb`
|
25
|
+
#
|
26
|
+
# The `.rb` suffix is optional for `confile` variations, but recommended.
|
27
|
+
# It is not optional for `config` b/c very old version of setup.rb script
|
28
|
+
# still in use by some projects use `.config` for it's own purposes.
|
29
|
+
#
|
30
|
+
# TODO: Yes, there are really too many choices for config file name, but
|
31
|
+
# we haven't been able to settle on a smaller list just yet. Please come
|
32
|
+
# argue with us about what's best.
|
33
|
+
#
|
34
|
+
CONFIG_FILE = '{.c,C,c}onfi{g.rb,le.rb,le}'
|
35
|
+
|
36
|
+
#
|
37
|
+
# When looking up config file, it one of these is found
|
38
|
+
# then there is no point to looking further.
|
39
|
+
#
|
40
|
+
ROOT_INDICATORS = %w{.git .hg _darcs .ruby}
|
41
|
+
|
42
|
+
#
|
43
|
+
# Load configuration file from local project or other gem.
|
44
|
+
#
|
45
|
+
# @param options [Hash] Load options.
|
46
|
+
#
|
47
|
+
# @option options [String] :from
|
48
|
+
# Name of gem or library.
|
49
|
+
#
|
50
|
+
def self.load(options={})
|
51
|
+
if from = options[:from]
|
52
|
+
file = Find.path(CONFIG_FILE, :from=>from).first
|
53
|
+
else
|
54
|
+
file = lookup(CONFIG_FILE)
|
55
|
+
end
|
56
|
+
new(file)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Initialize new Configuration object.
|
61
|
+
#
|
62
|
+
# @param [String] file
|
63
|
+
# Configuration file (optional).
|
64
|
+
#
|
65
|
+
def initialize(file=nil)
|
66
|
+
@file = file
|
67
|
+
|
68
|
+
@_config = Hash.new{ |h,k| h[k]=[] }
|
69
|
+
#@_onload = Hash.new{ |h,k| h[k]=[] }
|
70
|
+
|
71
|
+
# TODO: does this rescue make sense here?
|
72
|
+
begin
|
73
|
+
dsl = DSL.new(self)
|
74
|
+
dsl.instance_eval(File.read(file), file) if file
|
75
|
+
rescue => e
|
76
|
+
raise e if $DEBUG
|
77
|
+
warn e.message
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
def evaluate(*args, &block)
|
83
|
+
dsl = DSL.new(self)
|
84
|
+
dsl.instance_eval(*args, &block)
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Configure a tool.
|
89
|
+
#
|
90
|
+
# @param [Symbol] tool
|
91
|
+
# The name of the command or feature to configure.
|
92
|
+
#
|
93
|
+
# @param [Hash] opts
|
94
|
+
# Configuration options.
|
95
|
+
#
|
96
|
+
# @options opts [String] :command
|
97
|
+
# Name of command, or false if not a command configuration.
|
98
|
+
#
|
99
|
+
# @options opts [String] :feature
|
100
|
+
# Alternate require if differnt than command name.
|
101
|
+
#
|
102
|
+
# @options opts [String] :from
|
103
|
+
# Library from which to import configuration.
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# profile :coverage do
|
107
|
+
# config :qed, :from=>'qed'
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
def config(target, options={}, &block)
|
111
|
+
#options[:profile] = (options[:profile] || 'default').to_s
|
112
|
+
#options[:command] = command.to_s unless options.key?(:command)
|
113
|
+
#options[:feature] = command.to_s unless options.key?(:feature)
|
114
|
+
#command = options[:command].to_s
|
115
|
+
|
116
|
+
# IDEA: other import options such as local file?
|
117
|
+
|
118
|
+
configs_from(options).each do |c|
|
119
|
+
@_config[target.to_s] << c.copy(options)
|
120
|
+
end
|
121
|
+
|
122
|
+
return unless block
|
123
|
+
|
124
|
+
@_config[target.to_s] << Config.new(target, options, &block)
|
125
|
+
end
|
126
|
+
|
127
|
+
=begin
|
128
|
+
#
|
129
|
+
#
|
130
|
+
#
|
131
|
+
def onload(feature, options={}, &block)
|
132
|
+
#options[:profile] = (options[:profile] || 'default').to_s
|
133
|
+
|
134
|
+
#options[:feature] = feature.to_s unless options.key?(:feature)
|
135
|
+
#options[:command] = feature.to_s unless options.key?(:command)
|
136
|
+
|
137
|
+
feature = options[:feature].to_s
|
138
|
+
|
139
|
+
# IDEA: what about local file import?
|
140
|
+
configs_from(options).each do |c|
|
141
|
+
@_onload[feature] << c.copy(options)
|
142
|
+
end
|
143
|
+
|
144
|
+
return unless block
|
145
|
+
|
146
|
+
@_onload[feature] << Config.new(feature, options, &block)
|
147
|
+
end
|
148
|
+
=end
|
149
|
+
|
150
|
+
#
|
151
|
+
#
|
152
|
+
#
|
153
|
+
def [](feature)
|
154
|
+
@_config[feature.to_s]
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Iterate over each feature config.
|
159
|
+
#
|
160
|
+
# @example
|
161
|
+
# confgiuration.each do |feature, configs|
|
162
|
+
# configs.each do |config|
|
163
|
+
# ...
|
164
|
+
# end
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
def each(&block)
|
168
|
+
@_config.each(&block)
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# The number of feature configs.
|
173
|
+
#
|
174
|
+
def size
|
175
|
+
@_config.size
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Get a list of the defined configurations.
|
180
|
+
#
|
181
|
+
# @return [Array] List of all defined configurations.
|
182
|
+
#
|
183
|
+
def to_a
|
184
|
+
list = []
|
185
|
+
@_config.each do |feature, configs|
|
186
|
+
list.concat(configs)
|
187
|
+
end
|
188
|
+
list
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# @deprecated
|
193
|
+
#
|
194
|
+
alias :configurations :to_a
|
195
|
+
|
196
|
+
#
|
197
|
+
# Get a list of defined profiles names for the given +command+.
|
198
|
+
# use the current command if no +command+ is given.
|
199
|
+
#
|
200
|
+
def profile_names(command=nil)
|
201
|
+
command = command || Courtier.current_command
|
202
|
+
|
203
|
+
list = []
|
204
|
+
@_config.each do |feature, configs|
|
205
|
+
configs.each do |c|
|
206
|
+
if c.command?(command)
|
207
|
+
list << c.profile
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
list.uniq
|
212
|
+
end
|
213
|
+
|
214
|
+
#def inspect
|
215
|
+
# "#<Courtier::Configuration:#{object_id} @file=#{@file}>"
|
216
|
+
#end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
#
|
221
|
+
# Search upward from working directory.
|
222
|
+
#
|
223
|
+
def self.lookup(glob, flags=0)
|
224
|
+
pwd = File.expand_path(Dir.pwd)
|
225
|
+
home = File.expand_path('~')
|
226
|
+
while pwd != '/' && pwd != home
|
227
|
+
if file = Dir.glob(File.join(pwd, glob), flags).first
|
228
|
+
return file
|
229
|
+
end
|
230
|
+
break if ROOT_INDICATORS.any?{ |r| File.exist?(File.join(pwd, r)) }
|
231
|
+
pwd = File.dirname(pwd)
|
232
|
+
end
|
233
|
+
return nil
|
234
|
+
end
|
235
|
+
|
236
|
+
# TODO: other import options such as local file?
|
237
|
+
|
238
|
+
#
|
239
|
+
#
|
240
|
+
#
|
241
|
+
def configs_from(options)
|
242
|
+
from = options[:from]
|
243
|
+
list = []
|
244
|
+
|
245
|
+
return list unless from
|
246
|
+
|
247
|
+
if Array === from
|
248
|
+
from_name, from_opts = *from
|
249
|
+
else
|
250
|
+
from_name, from_opts = from, {}
|
251
|
+
end
|
252
|
+
|
253
|
+
from_config = Courtier.configuration(from_name)
|
254
|
+
|
255
|
+
from_opts[:feature] = options[:feature] unless from_opts.key?(:feature) if options[:feature]
|
256
|
+
from_opts[:command] = options[:command] unless from_opts.key?(:command) if options[:command]
|
257
|
+
from_opts[:profile] = options[:profile] unless from_opts.key?(:profile) if options[:profile]
|
258
|
+
|
259
|
+
from_opts[:feature] = from_opts[:feature].to_s if from_opts[:feature]
|
260
|
+
from_opts[:command] = from_opts[:command].to_s if from_opts[:command]
|
261
|
+
from_opts[:profile] = from_opts[:profile].to_s if from_opts[:profile]
|
262
|
+
|
263
|
+
from_config.each do |ftr, confs|
|
264
|
+
confs.each_with_index do |c, i|
|
265
|
+
if c.match?(from_opts)
|
266
|
+
list << c.copy(options)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
list
|
272
|
+
end
|
273
|
+
|
274
|
+
#
|
275
|
+
class DSL
|
276
|
+
|
277
|
+
#
|
278
|
+
#
|
279
|
+
#
|
280
|
+
def initialize(configuration)
|
281
|
+
@configuration = configuration
|
282
|
+
@_options = {}
|
283
|
+
end
|
284
|
+
|
285
|
+
#
|
286
|
+
#
|
287
|
+
#
|
288
|
+
def profile(name, &block)
|
289
|
+
raise SyntaxError, "nested profile sections" if @_options[:profile]
|
290
|
+
@_options[:profile] = name.to_s
|
291
|
+
instance_eval(&block)
|
292
|
+
@_options.delete(:profile)
|
293
|
+
end
|
294
|
+
|
295
|
+
#
|
296
|
+
# Profile block.
|
297
|
+
#
|
298
|
+
# @param [String,Symbol] name
|
299
|
+
# A profile name.
|
300
|
+
#
|
301
|
+
def profile(name, state={}, &block)
|
302
|
+
raise SyntaxError, "nested profile sections" if @_options[:profile]
|
303
|
+
original_state = @_options.dup
|
304
|
+
@_options.update(state)
|
305
|
+
@_options[:profile] = name.to_s
|
306
|
+
instance_eval(&block)
|
307
|
+
@_options = original_state
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
#
|
312
|
+
def config(command, options={}, &block)
|
313
|
+
nested_keys = @_options.keys & options.keys.map{|k| k.to_sym}
|
314
|
+
raise ArgumentError, "nested #{nested_keys.join(', ')}" unless nested_keys.empty?
|
315
|
+
|
316
|
+
options = @_options.merge(options)
|
317
|
+
@configuration.config(command, options, &block)
|
318
|
+
end
|
319
|
+
|
320
|
+
#
|
321
|
+
#
|
322
|
+
def onload(feature, options={}, &block)
|
323
|
+
nested_keys = @_options.keys & options.keys.map{|k| k.to_sym}
|
324
|
+
raise ArgumentError, "nested #{nested_keys.join(', ')}" unless nested_keys.empty?
|
325
|
+
|
326
|
+
options = @_options.merge(options)
|
327
|
+
options[:onload] = true
|
328
|
+
@configuration.config(feature, options, &block)
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|