rconf 0.5.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/README.rdoc +56 -0
- data/Rakefile +63 -0
- data/bin/rconf +102 -0
- data/examples/sample.rc +9 -0
- data/lib/rconf.rb +24 -0
- data/lib/rconf/command.rb +112 -0
- data/lib/rconf/configurator.rb +179 -0
- data/lib/rconf/configurator_registry.rb +63 -0
- data/lib/rconf/configurators/bundler_configurator.rb +85 -0
- data/lib/rconf/configurators/ruby_configurator.rb +151 -0
- data/lib/rconf/language.rb +91 -0
- data/lib/rconf/platform.rb +114 -0
- data/lib/rconf/platforms/darwin.rb +27 -0
- data/lib/rconf/platforms/linux.rb +40 -0
- data/lib/rconf/platforms/windows.rb +40 -0
- data/lib/rconf/progress_reporter.rb +72 -0
- data/lib/rconf/progress_reporters/base_reporter.rb +156 -0
- data/lib/rconf/progress_reporters/file_reporter.rb +58 -0
- data/lib/rconf/progress_reporters/stdout_reporter.rb +83 -0
- data/lib/rconf/ruby_extensions.rb +56 -0
- data/lib/rconf/trollop.rb +782 -0
- data/lib/rconf/version.rb +30 -0
- data/rconf.gemspec +24 -0
- data/spec/command_spec.rb +38 -0
- data/spec/configurator_spec.rb +64 -0
- data/spec/configurators/bundler_configurator_spec.rb +51 -0
- data/spec/configurators/ruby_configurator_spec.rb +60 -0
- data/spec/language_spec.rb +60 -0
- data/spec/platform_spec.rb +37 -0
- data/spec/progress_reporters/base_reporter_spec.rb +84 -0
- data/spec/progress_reporters/file_reporter_spec.rb +31 -0
- data/spec/progress_reporters/stdout_reporter_spec.rb +23 -0
- data/spec/ruby_extensions_spec.rb +35 -0
- data/spec/spec_helper.rb +21 -0
- metadata +129 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
# Configurator mixin, defines DSL and common validation method
|
15
|
+
class ConfiguratorRegistry
|
16
|
+
|
17
|
+
include Singleton
|
18
|
+
|
19
|
+
# Associate configurator with given key
|
20
|
+
#
|
21
|
+
# === Parameters
|
22
|
+
# key(Symbol):: Key configurator should be associated with
|
23
|
+
# value(Class):: Associated configurator class
|
24
|
+
#
|
25
|
+
# === Return
|
26
|
+
# value(Class):: Configurator class
|
27
|
+
def []=(key, value)
|
28
|
+
@configurators[key] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
# Configurator class for given key
|
32
|
+
#
|
33
|
+
# === Parameters
|
34
|
+
# key(String):: Configurator for given key
|
35
|
+
#
|
36
|
+
# === Return
|
37
|
+
# cfg_class(Constant):: Configurator class if there is one
|
38
|
+
# nil:: Otherwise
|
39
|
+
def [](key)
|
40
|
+
@configurators[key]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Iterate through all configurators
|
44
|
+
#
|
45
|
+
# === Block
|
46
|
+
# Block should take one argument which is the configurator being iterated on
|
47
|
+
#
|
48
|
+
# === Return
|
49
|
+
# true:: Always return true
|
50
|
+
def each(&blk)
|
51
|
+
@configurators.each(&blk)
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
# Initialize configurators hash
|
58
|
+
def initialize
|
59
|
+
@configurators = Hash.new
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
class BundlerConfigurator
|
15
|
+
|
16
|
+
DEFAULT_GEM_PATH = 'vendor/system_gems/cache'
|
17
|
+
|
18
|
+
include Configurator
|
19
|
+
|
20
|
+
register :bundler
|
21
|
+
|
22
|
+
description 'Installs bundler and runs "bundle install"'
|
23
|
+
|
24
|
+
settings :bundler_version => 'Version of bundler gem, e.g. "1.0.10"',
|
25
|
+
:bundler_gem_path => 'Path to bundler gem, e.g. "vendor/system_gems/cache"'
|
26
|
+
|
27
|
+
validate_has_settings :bundler_version
|
28
|
+
|
29
|
+
# Install bundler if needed and run bundle install
|
30
|
+
#
|
31
|
+
# === Return
|
32
|
+
# true:: Always return true
|
33
|
+
def run_linux
|
34
|
+
report_check("Checking for bundler #{bundler_version}")
|
35
|
+
res = Command.execute('bundle', '--version')
|
36
|
+
success = (res.output =~ /#{bundler_version}/)
|
37
|
+
report_result(success)
|
38
|
+
install_bundler(res.success?) unless success
|
39
|
+
report_check('Installing gems')
|
40
|
+
res = Command.execute('bundle', 'install', :abort_on_failure => 'Failed to install gems')
|
41
|
+
report_success
|
42
|
+
true
|
43
|
+
end
|
44
|
+
alias :run_darwin :run_linux
|
45
|
+
|
46
|
+
# Not implemented on windows (no bundler gem there)
|
47
|
+
#
|
48
|
+
# === Raise
|
49
|
+
# (Exception):: Always raise
|
50
|
+
def run_windows
|
51
|
+
raise "Bundler is not supported on Windows!"
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
# Install bundler from gem in cache
|
57
|
+
#
|
58
|
+
# === Parameters
|
59
|
+
# exists(FalseClass|TrueClass):: Whether bundler is already installed
|
60
|
+
# (but is the wrong version)
|
61
|
+
#
|
62
|
+
# === Return
|
63
|
+
# true:: Always return true
|
64
|
+
#
|
65
|
+
# === Raise
|
66
|
+
# (Exception):: If bundler gem cannot be found or installed
|
67
|
+
def install_bundler(exists)
|
68
|
+
if exists
|
69
|
+
report_check('Uninstalling existing versions of bundler')
|
70
|
+
res = Command.execute('gem', 'uninstall', 'bundler', '-a', '-x',
|
71
|
+
:abort_on_failure => 'Failed to uninstall bundler')
|
72
|
+
report_success
|
73
|
+
end
|
74
|
+
report_check("Installing bundler #{bundler_version}")
|
75
|
+
bundler_gem_path DEFAULT_GEM_PATH unless bundler_gem_path
|
76
|
+
bundler_file = File.join(bundler_gem_path, "bundler-#{bundler_version}.gem")
|
77
|
+
report_fatal("Missing bundler gem at #{bundler_file}") unless File.exist?(bundler_file)
|
78
|
+
res = Command.execute('gem','install', bundler_file, '--no-ri', '--no-rdoc',
|
79
|
+
:abort_on_failure => 'Failed to install bundler')
|
80
|
+
report_success
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
class RubyConfigurator
|
15
|
+
|
16
|
+
# RVM version used to install rubies
|
17
|
+
RVM_VERSION = '1.2.6'
|
18
|
+
|
19
|
+
include Configurator
|
20
|
+
|
21
|
+
register :ruby
|
22
|
+
|
23
|
+
description "Installs ruby interpreter and rubygems.\n" +
|
24
|
+
'Installs and uses rvm on supported (i.e. non-Windows) platforms'
|
25
|
+
|
26
|
+
settings :ruby_version => 'Ruby version using rvm notation (see "rvm list known")',
|
27
|
+
:rubygems_version => 'Rubygems version, e.g. "1.3.7"',
|
28
|
+
:gemset => 'Gemset to be used for platforms supporting rvm'
|
29
|
+
|
30
|
+
validate_has_settings :ruby_version, :rubygems_version
|
31
|
+
|
32
|
+
# Switch to ruby version defined in settings
|
33
|
+
# Use rvm and install it if needed
|
34
|
+
#
|
35
|
+
# === Return
|
36
|
+
# true:: Always return true
|
37
|
+
def run_linux
|
38
|
+
check_rvm(RVM_VERSION)
|
39
|
+
report_check("Checking whether #{ruby_version} is the active ruby")
|
40
|
+
out = Command.execute('rvm', 'list').output
|
41
|
+
if out =~ /^=> #{ruby_version.gsub('.', '\\.')}/
|
42
|
+
report_success
|
43
|
+
else
|
44
|
+
report_failure
|
45
|
+
report_check("Switching to #{ruby_version}")
|
46
|
+
out = Command.execute('rvm', 'use', ruby_version).output
|
47
|
+
case out
|
48
|
+
when /is not installed\./
|
49
|
+
report_failure
|
50
|
+
report_fatal "Failed to install #{ruby}: #{@out}" if @out
|
51
|
+
@out = install_ruby(ruby_version)
|
52
|
+
run
|
53
|
+
return true
|
54
|
+
when /^Using /
|
55
|
+
report_success
|
56
|
+
check_rvmrc
|
57
|
+
post_note 'Configuration required switching the active ruby, please "cd" into the project directory again to activate it'
|
58
|
+
else
|
59
|
+
report_fatal("Failed to use #{ruby_version}:\n#{out}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if gemset
|
63
|
+
report_check("Switching to gemset #{gemset}")
|
64
|
+
res = Command.execute('rvm', 'gemset', 'use', gemset,
|
65
|
+
:abort_on_failure => "Failed to switch to gemset '#{gemset}'")
|
66
|
+
report_success
|
67
|
+
end
|
68
|
+
Command.set_prefix("rvm #{ruby_version}@#{gemset} exec --")
|
69
|
+
true
|
70
|
+
end
|
71
|
+
alias :run_darwin :run_linux
|
72
|
+
|
73
|
+
# Switch to ruby version defined in settings
|
74
|
+
# TBD
|
75
|
+
#
|
76
|
+
# === Return
|
77
|
+
# true:: Always return true
|
78
|
+
def run_windows
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Check whether the right version of RVM is installed and install it if not
|
84
|
+
#
|
85
|
+
# === Parameters
|
86
|
+
# version(String):: Version of RVM to be checked, e.g. '1.2.6'
|
87
|
+
#
|
88
|
+
# === Return
|
89
|
+
# true:: Always return true
|
90
|
+
def check_rvm(version)
|
91
|
+
report_check("Checking that rvm #{version} is installed")
|
92
|
+
out = Command.execute('rvm', '--version').output
|
93
|
+
if out =~ /rvm #{RVM_VERSION.gsub('.', '\\.')}/
|
94
|
+
report_success
|
95
|
+
else
|
96
|
+
report_failure
|
97
|
+
report_check("Installing rvm #{version}")
|
98
|
+
rvm_src = File.join(ENV['HOME'] || '/root', '.rvm/src')
|
99
|
+
FileUtils.mkdir_p(rvm_src)
|
100
|
+
Dir.chdir(rvm_src) do
|
101
|
+
res = Command.execute('curl', '-O', '-f',
|
102
|
+
"http://rvm.beginrescueend.com/releases/rvm-#{version}.tar.gz",
|
103
|
+
:abort_on_failure => "Failed to download rvm #{version}")
|
104
|
+
Command.execute('tar', 'zxf', "rvm-#{version}.tar.gz")
|
105
|
+
end
|
106
|
+
Dir.chdir(File.join(rvm_src, "rvm-#{version}")) do
|
107
|
+
res = Command.execute('./install', :abort_on_failure => "Failed to install rvm #{version}")
|
108
|
+
end
|
109
|
+
report_success
|
110
|
+
end
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
# Install given ruby version using rvm
|
115
|
+
#
|
116
|
+
# === Parameters
|
117
|
+
# ruby(String):: Ruby version compatible with rvm
|
118
|
+
#
|
119
|
+
# === Return
|
120
|
+
# out(String):: Installation output
|
121
|
+
def install_ruby(ruby)
|
122
|
+
report_check("Installing #{ruby} (this will take a while, please be patient)")
|
123
|
+
res = Command.execute('rvm', 'install', ruby)
|
124
|
+
report_result(res.success?)
|
125
|
+
res.output
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check .rvmrc and its content
|
129
|
+
#
|
130
|
+
# === Return
|
131
|
+
# true:: Always return true
|
132
|
+
def check_rvmrc
|
133
|
+
report_check('Setting up .rvmrc')
|
134
|
+
begin
|
135
|
+
File.open('.rvmrc', 'w') do |f|
|
136
|
+
f.puts "rvm #{ruby_version}@#{gemset}"
|
137
|
+
f.puts "type -P rconf &>/dev/null && { rconf; }"
|
138
|
+
f.puts "type -P rconf &>/dev/null || { echo 'rconf not installed, skipping (see .rvmrc)'; }"
|
139
|
+
end
|
140
|
+
Command.execute('rvm', 'trust', 'rvmrc')
|
141
|
+
report_success
|
142
|
+
rescue Exception => e
|
143
|
+
report_failure
|
144
|
+
report_error(e.message)
|
145
|
+
end
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
module RightConf
|
13
|
+
|
14
|
+
# DSL implementation
|
15
|
+
class Language
|
16
|
+
|
17
|
+
# List of configurators resulting from parsing a configuration
|
18
|
+
attr_reader :configurators
|
19
|
+
|
20
|
+
# Errors generated by configurators validations if any
|
21
|
+
attr_reader :validation_errors
|
22
|
+
|
23
|
+
# Load given file and run content to retrieve configurators
|
24
|
+
#
|
25
|
+
# === Parameters
|
26
|
+
# file(String):: Path to file being loaded
|
27
|
+
#
|
28
|
+
# === Result
|
29
|
+
# lang(Language):: Instance initialized from file
|
30
|
+
def self.load(file)
|
31
|
+
begin
|
32
|
+
content = IO.read(file)
|
33
|
+
rescue Exception => e
|
34
|
+
raise "Failed to load '#{file}': #{e.message}"
|
35
|
+
end
|
36
|
+
parse(content)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Parse given configuration text
|
40
|
+
#
|
41
|
+
# === Parameters
|
42
|
+
# content(String):: Content to be parsed
|
43
|
+
#
|
44
|
+
# === Result
|
45
|
+
# lang(Language):: Instance initialized from content
|
46
|
+
def self.parse(content)
|
47
|
+
lang = new
|
48
|
+
lang.instance_eval(content)
|
49
|
+
lang
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Initialize configurators and validation errors lists
|
55
|
+
# Do not call directly, instead call 'load'
|
56
|
+
def initialize
|
57
|
+
@configurators = Array.new
|
58
|
+
@validation_errors = Array.new
|
59
|
+
end
|
60
|
+
|
61
|
+
# Each missing method should correspond to a configurator section.
|
62
|
+
# Such sections consist of a block which gets eval'ed in the contect of the
|
63
|
+
# corresponding configurator instance.
|
64
|
+
#
|
65
|
+
# === Parameters
|
66
|
+
# meth(Symbol):: Method symbol, should be a configurator
|
67
|
+
# args(Array):: List of arguments
|
68
|
+
# blk(Proc):: Block to be evaled in configurator context
|
69
|
+
#
|
70
|
+
# === Return
|
71
|
+
# true:: Always return true
|
72
|
+
def method_missing(meth, *args, &blk)
|
73
|
+
if blk
|
74
|
+
klass = ConfiguratorRegistry[meth]
|
75
|
+
if klass
|
76
|
+
configurator = klass.new(*args)
|
77
|
+
configurator.instance_eval(&blk)
|
78
|
+
error = configurator.validate
|
79
|
+
@validation_errors << error if error
|
80
|
+
@configurators << configurator
|
81
|
+
else
|
82
|
+
@validation_errors << "Unknown configurator '#{meth}'"
|
83
|
+
end
|
84
|
+
else
|
85
|
+
@validation_errors << "Invalid syntax, expecting block after '#{meth}'"
|
86
|
+
end
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright (C) 2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and
|
10
|
+
# the licensee
|
11
|
+
|
12
|
+
require 'rbconfig'
|
13
|
+
|
14
|
+
module RightConf
|
15
|
+
|
16
|
+
class Platform
|
17
|
+
|
18
|
+
include Singleton
|
19
|
+
|
20
|
+
|
21
|
+
# Generic platform family
|
22
|
+
#
|
23
|
+
# === Return
|
24
|
+
# family(Symbol):: One of :linux, :windows or :darwin
|
25
|
+
def family
|
26
|
+
@family ||= case RbConfig::CONFIG['host_os']
|
27
|
+
when /mswin|win32|dos|mingw|cygwin/i then :windows
|
28
|
+
when /darwin/i then :darwin
|
29
|
+
when /linux/i then :linux
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is current platform linux?
|
34
|
+
#
|
35
|
+
# === Return
|
36
|
+
# true:: If current platform is linux
|
37
|
+
# false:: Otherwise
|
38
|
+
def linux?
|
39
|
+
return family == :linux
|
40
|
+
end
|
41
|
+
|
42
|
+
# Is current platform darwin?
|
43
|
+
#
|
44
|
+
# === Return
|
45
|
+
# true:: If current platform is darwin
|
46
|
+
# false:: Otherwise
|
47
|
+
def darwin?
|
48
|
+
return family == :darwin
|
49
|
+
end
|
50
|
+
# Is current platform windows?
|
51
|
+
#
|
52
|
+
# === Return
|
53
|
+
# true:: If current platform is Windows
|
54
|
+
# false:: Otherwise
|
55
|
+
def windows?
|
56
|
+
return family == :windows
|
57
|
+
end
|
58
|
+
|
59
|
+
# Call platform specific implementation of method whose symbol is returned
|
60
|
+
# by the passed in block. Arguments are passed through.
|
61
|
+
# e.g.
|
62
|
+
#
|
63
|
+
# Platform.dispatch(2) { :echo }
|
64
|
+
#
|
65
|
+
# will result in 'echo_linux(2)' being executed in self if running on linux,
|
66
|
+
# 'echo_windows(2)' if running on Windows and 'echo_darwin(2)' if on
|
67
|
+
# Mac OS X. Note that the method is run in the instance of the caller.
|
68
|
+
#
|
69
|
+
# === Parameters
|
70
|
+
# args:: Pass-through arguments
|
71
|
+
#
|
72
|
+
# === Block
|
73
|
+
# Given block should not take any argument and return a symbol for the
|
74
|
+
# method that should be called
|
75
|
+
#
|
76
|
+
# === Return
|
77
|
+
# res(ObjecT):: Result returned by platform specific implementation
|
78
|
+
def dispatch(*args, &blk)
|
79
|
+
raise "Platform.dispatch requires a block" unless blk
|
80
|
+
binding = blk.binding.eval('self')
|
81
|
+
meth = blk.call
|
82
|
+
target = dispatch_candidates(meth).detect do |candidate|
|
83
|
+
binding.respond_to?(candidate)
|
84
|
+
end
|
85
|
+
raise "No platform dispatch target found in #{binding.class} for " +
|
86
|
+
"'#{meth.inspect}', tried " + dispatch_candidates(meth).join(', ') unless target
|
87
|
+
binding.__send__(target, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
# Load platform specific implementation
|
93
|
+
def initialize
|
94
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'platforms', family.to_s))
|
95
|
+
init
|
96
|
+
end
|
97
|
+
|
98
|
+
# Candidate platform specific methods for given prefix
|
99
|
+
# Ordered by most platform specific to most generic
|
100
|
+
#
|
101
|
+
# === Parameters
|
102
|
+
# prefix(String):: Method prefix
|
103
|
+
#
|
104
|
+
# === Return
|
105
|
+
# candidates(Array):: List of potential candidates
|
106
|
+
def dispatch_candidates(prefix)
|
107
|
+
candidates = ["#{prefix}_#{family}_#{flavor}_#{release}",
|
108
|
+
"#{prefix}_#{family}_#{flavor}",
|
109
|
+
"#{prefix}_#{family}"]
|
110
|
+
candidates.map(&:to_sym)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|