rc 0.2.0 → 0.3.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/.index +66 -0
- data/.rubyrc +88 -0
- data/.yardopts +8 -0
- data/HISTORY.md +40 -0
- data/LICENSE.txt +27 -0
- data/README.md +194 -0
- data/demo/00_concept.md +23 -0
- data/demo/01_config.md +14 -0
- data/demo/02_configuration.md +51 -0
- data/demo/03_import.md +48 -0
- data/demo/06_interface.md +39 -0
- data/demo/applique/ae.rb +1 -0
- data/demo/applique/file.rb +8 -0
- data/demo/applique/fixture.rb +10 -0
- data/demo/applique/fixture/.ruby +11 -0
- data/demo/cov.rb +7 -0
- data/lib/c.rb +8 -0
- data/lib/rc.rb +10 -0
- data/lib/rc/api.rb +4 -0
- data/lib/rc/config.rb +305 -0
- data/lib/rc/config_filter.rb +110 -0
- data/lib/rc/configuration.rb +362 -0
- data/lib/rc/constants.rb +9 -0
- data/lib/rc/core_ext.rb +6 -0
- data/lib/rc/core_ext/argv.rb +22 -0
- data/lib/rc/core_ext/hash.rb +17 -0
- data/lib/rc/core_ext/kernel.rb +38 -0
- data/lib/rc/core_ext/string.rb +20 -0
- data/lib/rc/core_ext/symbol.rb +8 -0
- data/lib/rc/dsl.rb +72 -0
- data/lib/rc/interface.rb +338 -0
- data/lib/rc/properties.rb +108 -0
- data/lib/rc/required.rb +10 -0
- data/lib/rc/setup.rb +57 -0
- data/lib/rc/tweaks/rake.rb +31 -0
- metadata +118 -22
@@ -0,0 +1,110 @@
|
|
1
|
+
module RC
|
2
|
+
|
3
|
+
# To be quite honest I have forgotten the purpose of this class
|
4
|
+
# and it is no longer being used, so it should be deleted. But
|
5
|
+
# I am holding off a bit, in case I recall why it was here, in
|
6
|
+
# order to be sure.
|
7
|
+
#
|
8
|
+
class ConfigFilter
|
9
|
+
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
#
|
13
|
+
# Initialize new ConfigFilter.
|
14
|
+
#
|
15
|
+
# @param [Array<Config>] configuration
|
16
|
+
# List if Config instances.
|
17
|
+
#
|
18
|
+
def initialize(configuration, criteria={})
|
19
|
+
@configuration = configuration
|
20
|
+
@criteria = criteria
|
21
|
+
|
22
|
+
@list = []
|
23
|
+
|
24
|
+
configuration.each do |c|
|
25
|
+
@list << c if c.match?(criteria)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
#
|
31
|
+
#
|
32
|
+
def tool
|
33
|
+
@criteria[:tool]
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
#
|
38
|
+
#
|
39
|
+
def profile
|
40
|
+
@criteria[:profile]
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Returns list of profiles.
|
45
|
+
#
|
46
|
+
def profiles
|
47
|
+
@list.map{ |c| c.profile }
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
#
|
52
|
+
#
|
53
|
+
def [](subset)
|
54
|
+
return method_missing(:[]) if profile
|
55
|
+
if tool
|
56
|
+
criteria = @criteria.dup
|
57
|
+
criteria[:profile] = subset
|
58
|
+
else
|
59
|
+
criteria = @criteria.dup
|
60
|
+
criteria[:tool] = subset
|
61
|
+
end
|
62
|
+
self.class.new(@configuration, criteria)
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
#
|
67
|
+
#
|
68
|
+
def each(&block)
|
69
|
+
@list.each do
|
70
|
+
block
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
#
|
76
|
+
#
|
77
|
+
def size
|
78
|
+
@list.size
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Call each config.
|
83
|
+
#
|
84
|
+
def call(*args)
|
85
|
+
@list.each do |c|
|
86
|
+
if c.profile?(RC.current_profile)
|
87
|
+
c.call(*args)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Convert to Proc.
|
94
|
+
#
|
95
|
+
def to_proc(exec=false)
|
96
|
+
list = @list
|
97
|
+
if exec
|
98
|
+
Proc.new do |*args|
|
99
|
+
list.each{ |c| instance_exec(*args, &c) }
|
100
|
+
end
|
101
|
+
else
|
102
|
+
Proc.new do |*args|
|
103
|
+
list.each{ |c| c.call(*args) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,362 @@
|
|
1
|
+
module RC
|
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
|
+
# Runtime configuration file glob pattern.
|
15
|
+
#
|
16
|
+
CONFIG_FILE = '.ruby{rc,}'
|
17
|
+
|
18
|
+
class << self
|
19
|
+
#
|
20
|
+
# Load configuration file from local project or other gem.
|
21
|
+
#
|
22
|
+
# @param options [Hash] Load options.
|
23
|
+
#
|
24
|
+
# @option options [String] :from
|
25
|
+
# Name of gem or library.
|
26
|
+
#
|
27
|
+
def load(options={})
|
28
|
+
if options[:from]
|
29
|
+
load_from(options[:from])
|
30
|
+
else
|
31
|
+
load_local()
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Load configuration from another gem.
|
37
|
+
#
|
38
|
+
def load_from(gem)
|
39
|
+
files = Find.path(CONFIG_FILE, :from=>gem)
|
40
|
+
file = files.find{ |f| File.file?(f) }
|
41
|
+
new(*file)
|
42
|
+
|
43
|
+
#if file
|
44
|
+
# paths = [file]
|
45
|
+
#else
|
46
|
+
# #paths = Find.path(CONFIG_DIR + '/**/*', :from=>gem)
|
47
|
+
#end
|
48
|
+
#files = paths.select{ |path| File.file?(path) }
|
49
|
+
#new(*files)
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Load configuration for current project.
|
54
|
+
#
|
55
|
+
def load_local
|
56
|
+
files = lookup(CONFIG_FILE)
|
57
|
+
file = files.find{ |f| File.file?(f) }
|
58
|
+
new(*file)
|
59
|
+
|
60
|
+
#if file
|
61
|
+
# paths = [file]
|
62
|
+
#else
|
63
|
+
# dir = lookup(CONFIG_DIR).find{ |f| File.directory?(f) }
|
64
|
+
# paths = dir ? Dir.glob(File.join(dir, '**/*')) : []
|
65
|
+
#end
|
66
|
+
#files = paths.select{ |path| File.file?(path) }
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
#
|
72
|
+
# Search upward from working directory.
|
73
|
+
#
|
74
|
+
def lookup(glob, flags=0)
|
75
|
+
pwd = File.expand_path(Dir.pwd)
|
76
|
+
home = File.expand_path('~')
|
77
|
+
while pwd != '/' && pwd != home
|
78
|
+
paths = Dir.glob(File.join(pwd, glob), flags)
|
79
|
+
return paths unless paths.empty?
|
80
|
+
break if ROOT_INDICATORS.any?{ |r| File.exist?(File.join(pwd, r)) }
|
81
|
+
pwd = File.dirname(pwd)
|
82
|
+
end
|
83
|
+
return []
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Initialize new Configuration object.
|
90
|
+
#
|
91
|
+
# @param [Array<String>] files
|
92
|
+
# Configuration files (optional).
|
93
|
+
#
|
94
|
+
def initialize(*files)
|
95
|
+
@files = files
|
96
|
+
|
97
|
+
@_config = Hash.new{ |h,k| h[k]=[] }
|
98
|
+
#@_onload = Hash.new{ |h,k| h[k]=[] }
|
99
|
+
|
100
|
+
load_files(*files)
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Import other runtime configuration files.
|
105
|
+
#
|
106
|
+
# @param [String] glob
|
107
|
+
# File pattern of configutation files to load.
|
108
|
+
#
|
109
|
+
# @param opts [Hash] Load options.
|
110
|
+
#
|
111
|
+
# @option opts [String] :from
|
112
|
+
# Name of gem or library.
|
113
|
+
#
|
114
|
+
# @option opts [Boolean] :first
|
115
|
+
# Only match a single file.
|
116
|
+
#
|
117
|
+
def import(glob, opts={})
|
118
|
+
paths = []
|
119
|
+
|
120
|
+
glob = glob + '**/*' if glob.end_with?('/')
|
121
|
+
|
122
|
+
if from = opts[:from]
|
123
|
+
paths = Find.path(glob, :from=>from)
|
124
|
+
else
|
125
|
+
if glob.start_with?('/')
|
126
|
+
if root = lookup_root
|
127
|
+
glob = File.join(root, glob)
|
128
|
+
else
|
129
|
+
raise "no project root for #{glob}" unless root
|
130
|
+
end
|
131
|
+
end
|
132
|
+
paths = Dir.glob(glob)
|
133
|
+
end
|
134
|
+
|
135
|
+
paths = paths.select{ |path| File.file?(path) }
|
136
|
+
paths = paths[0..0] if opts[:first]
|
137
|
+
|
138
|
+
load_files(*paths)
|
139
|
+
|
140
|
+
paths.empty? ? nil : paths
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Load configuration files.
|
145
|
+
#
|
146
|
+
# TODO: begin/rescue around instance_eval?
|
147
|
+
#
|
148
|
+
# TODO: Does each file need it's own DSL instance?
|
149
|
+
#
|
150
|
+
def load_files(*files)
|
151
|
+
dsl = DSL.new(self)
|
152
|
+
files.each do |file|
|
153
|
+
next unless File.file?(file) # TODO: warn ?
|
154
|
+
#begin
|
155
|
+
dsl.instance_eval(File.read(file), file)
|
156
|
+
#rescue => e
|
157
|
+
# raise e if $DEBUG
|
158
|
+
# warn e.message
|
159
|
+
#end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
alias :load_file :load_files
|
164
|
+
|
165
|
+
#
|
166
|
+
# Evaluate configuration code.
|
167
|
+
#
|
168
|
+
# @yieldparm cfg
|
169
|
+
# Configuration code block.
|
170
|
+
#
|
171
|
+
def evaluate(*args, &cfg)
|
172
|
+
dsl = DSL.new(self)
|
173
|
+
dsl.instance_eval(*args, &cfg)
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Configure a commandline tool or feature.
|
178
|
+
#
|
179
|
+
# @param [Symbol] target
|
180
|
+
# The name of the command or feature to configure.
|
181
|
+
#
|
182
|
+
# @param [Hash] opts
|
183
|
+
# Configuration options.
|
184
|
+
#
|
185
|
+
# @options opts [String] :command
|
186
|
+
# Name of command, or false if not a command configuration.
|
187
|
+
#
|
188
|
+
# @options opts [String] :feature
|
189
|
+
# Alternate require if differnt than command name.
|
190
|
+
#
|
191
|
+
# @options opts [String] :from
|
192
|
+
# Library from which to import configuration.
|
193
|
+
#
|
194
|
+
# @example
|
195
|
+
# profile :coverage do
|
196
|
+
# config :qed, :from=>'qed'
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
def config(target, options={}, &block)
|
200
|
+
#options[:profile] = (options[:profile] || 'default').to_s
|
201
|
+
#options[:command] = command.to_s unless options.key?(:command)
|
202
|
+
#options[:feature] = command.to_s unless options.key?(:feature)
|
203
|
+
#command = options[:command].to_s
|
204
|
+
|
205
|
+
# IDEA: other import options such as local file?
|
206
|
+
|
207
|
+
configs_from(options).each do |c|
|
208
|
+
@_config[target.to_s] << c.copy(options)
|
209
|
+
end
|
210
|
+
|
211
|
+
return unless block
|
212
|
+
|
213
|
+
@_config[target.to_s] << Config.new(target, options, &block)
|
214
|
+
end
|
215
|
+
|
216
|
+
=begin
|
217
|
+
#
|
218
|
+
#
|
219
|
+
#
|
220
|
+
def onload(feature, options={}, &block)
|
221
|
+
#options[:profile] = (options[:profile] || 'default').to_s
|
222
|
+
|
223
|
+
#options[:feature] = feature.to_s unless options.key?(:feature)
|
224
|
+
#options[:command] = feature.to_s unless options.key?(:command)
|
225
|
+
|
226
|
+
feature = options[:feature].to_s
|
227
|
+
|
228
|
+
# IDEA: what about local file import?
|
229
|
+
configs_from(options).each do |c|
|
230
|
+
@_onload[feature] << c.copy(options)
|
231
|
+
end
|
232
|
+
|
233
|
+
return unless block
|
234
|
+
|
235
|
+
@_onload[feature] << Config.new(feature, options, &block)
|
236
|
+
end
|
237
|
+
=end
|
238
|
+
|
239
|
+
#
|
240
|
+
#
|
241
|
+
#
|
242
|
+
def [](feature)
|
243
|
+
@_config[feature.to_s]
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
# Iterate over each feature config.
|
248
|
+
#
|
249
|
+
# @example
|
250
|
+
# confgiuration.each do |feature, configs|
|
251
|
+
# configs.each do |config|
|
252
|
+
# ...
|
253
|
+
# end
|
254
|
+
# end
|
255
|
+
#
|
256
|
+
def each(&block)
|
257
|
+
@_config.each(&block)
|
258
|
+
end
|
259
|
+
|
260
|
+
#
|
261
|
+
# The number of feature configs.
|
262
|
+
#
|
263
|
+
def size
|
264
|
+
@_config.size
|
265
|
+
end
|
266
|
+
|
267
|
+
#
|
268
|
+
# Get a list of the defined configurations.
|
269
|
+
#
|
270
|
+
# @return [Array] List of all defined configurations.
|
271
|
+
#
|
272
|
+
def to_a
|
273
|
+
list = []
|
274
|
+
@_config.each do |feature, configs|
|
275
|
+
list.concat(configs)
|
276
|
+
end
|
277
|
+
list
|
278
|
+
end
|
279
|
+
|
280
|
+
#
|
281
|
+
# @deprecated
|
282
|
+
#
|
283
|
+
alias :configurations :to_a
|
284
|
+
|
285
|
+
#
|
286
|
+
# Get a list of defined profiles names for the given +command+.
|
287
|
+
# use the current command if no +command+ is given.
|
288
|
+
#
|
289
|
+
def profile_names(command=nil)
|
290
|
+
command = command || RC.current_command
|
291
|
+
|
292
|
+
list = []
|
293
|
+
@_config.each do |feature, configs|
|
294
|
+
configs.each do |c|
|
295
|
+
if c.command?(command)
|
296
|
+
list << c.profile
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
list.uniq
|
301
|
+
end
|
302
|
+
|
303
|
+
#def inspect
|
304
|
+
# "#<RC::Configuration:#{object_id} @file=#{@file}>"
|
305
|
+
#end
|
306
|
+
|
307
|
+
private
|
308
|
+
|
309
|
+
# TODO: other import options such as local file?
|
310
|
+
|
311
|
+
#
|
312
|
+
#
|
313
|
+
#
|
314
|
+
def configs_from(options)
|
315
|
+
from = options[:from]
|
316
|
+
list = []
|
317
|
+
|
318
|
+
return list unless from
|
319
|
+
|
320
|
+
if Array === from
|
321
|
+
from_name, from_opts = *from
|
322
|
+
else
|
323
|
+
from_name, from_opts = from, {}
|
324
|
+
end
|
325
|
+
|
326
|
+
from_config = RC.configuration(from_name)
|
327
|
+
|
328
|
+
from_opts[:feature] = options[:feature] unless from_opts.key?(:feature) if options[:feature]
|
329
|
+
from_opts[:command] = options[:command] unless from_opts.key?(:command) if options[:command]
|
330
|
+
from_opts[:profile] = options[:profile] unless from_opts.key?(:profile) if options[:profile]
|
331
|
+
|
332
|
+
from_opts[:feature] = from_opts[:feature].to_s if from_opts[:feature]
|
333
|
+
from_opts[:command] = from_opts[:command].to_s if from_opts[:command]
|
334
|
+
from_opts[:profile] = from_opts[:profile].to_s if from_opts[:profile]
|
335
|
+
|
336
|
+
from_config.each do |ftr, confs|
|
337
|
+
confs.each_with_index do |c, i|
|
338
|
+
if c.match?(from_opts)
|
339
|
+
list << c.copy(options)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
list
|
345
|
+
end
|
346
|
+
|
347
|
+
#
|
348
|
+
# Search upward from project root directory.
|
349
|
+
#
|
350
|
+
def lookup_root
|
351
|
+
pwd = File.expand_path(Dir.pwd)
|
352
|
+
home = File.expand_path('~')
|
353
|
+
while pwd != '/' && pwd != home
|
354
|
+
return pwd if ROOT_INDICATORS.any?{ |r| File.exist?(File.join(pwd, r)) }
|
355
|
+
pwd = File.dirname(pwd)
|
356
|
+
end
|
357
|
+
return nil
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
end
|