courtier 0.2.0
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/.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
|