warningshot 0.9.4 → 0.9.5

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.
Files changed (51) hide show
  1. data/CHANGELOG +8 -0
  2. data/CONTRIBUTORS +2 -1
  3. data/README +86 -6
  4. data/Rakefile +4 -3
  5. data/TODO +1 -147
  6. data/bin/warningshot +11 -7
  7. data/lib/resolvers/core_lib_resolver.rb +2 -3
  8. data/lib/resolvers/directory_resolver.rb +1 -1
  9. data/lib/resolvers/file_resolver.rb +35 -17
  10. data/lib/resolvers/gem_resolver.rb +81 -60
  11. data/lib/resolvers/integrity_resolver.rb +10 -11
  12. data/lib/resolvers/manual_resolver.rb +15 -3
  13. data/lib/resolvers/permission_resolver.rb +6 -8
  14. data/lib/resolvers/symlink_resolver.rb +13 -8
  15. data/lib/resolvers/url_resolver.rb +28 -41
  16. data/lib/warningshot.rb +10 -7
  17. data/lib/warningshot/config.rb +254 -0
  18. data/lib/{warning_shot → warningshot}/dependency_resolver.rb +38 -17
  19. data/lib/{warning_shot → warningshot}/growl.rb +2 -0
  20. data/lib/{warning_shot → warningshot}/logger.rb +2 -0
  21. data/lib/{warning_shot → warningshot}/resolver.rb +177 -89
  22. data/lib/warningshot/suite.rb +4 -0
  23. data/lib/{warning_shot → warningshot}/template_generator.rb +4 -1
  24. data/lib/{warning_shot → warningshot}/version.rb +3 -1
  25. data/lib/warningshot/warning_shot.rb +187 -0
  26. data/tasks/gemspec.rb +3 -16
  27. data/tasks/yard.rb +1 -1
  28. data/templates/gems.yml +1 -0
  29. data/test/data/faux_test.yml +5 -0
  30. data/test/data/faux_test_resolver.rb +21 -0
  31. data/test/data/mock_resolver.rb +11 -5
  32. data/test/log/warningshot.log +3051 -532
  33. data/test/spec/unit/resolvers/core_lib_resolver_spec.rb +1 -1
  34. data/test/spec/unit/resolvers/directory_resolver_spec.rb +1 -1
  35. data/test/spec/unit/resolvers/file_resolver_spec.rb +9 -13
  36. data/test/spec/unit/resolvers/gem_resolver_spec.rb +108 -32
  37. data/test/spec/unit/resolvers/integrity_resolver_spec.rb +6 -6
  38. data/test/spec/unit/resolvers/permission_resolver_spec.rb +2 -2
  39. data/test/spec/unit/resolvers/symlink_resolver_spec.rb +8 -1
  40. data/test/spec/unit/resolvers/url_resolver_spec.rb +10 -10
  41. data/test/spec/unit/warningshot/config_spec.rb +57 -0
  42. data/test/spec/unit/{warning_shot → warningshot}/dependency_resolver_spec.rb +18 -9
  43. data/test/spec/unit/{warning_shot → warningshot}/resolver_spec.rb +54 -79
  44. data/test/spec/unit/{warning_shot → warningshot}/template_generator_spec.rb +1 -1
  45. data/test/spec/unit/{warning_shot → warningshot}/version_spec.rb +0 -0
  46. data/test/spec/unit/{warning_shot → warningshot}/warning_shot_spec.rb +0 -0
  47. metadata +24 -26
  48. data/lib/warning_shot/config.rb +0 -132
  49. data/lib/warning_shot/warning_shot.rb +0 -130
  50. data/test/spec/spec.opts.zoiks +0 -0
  51. data/test/spec/unit/warning_shot/config_spec.rb +0 -35
@@ -0,0 +1,254 @@
1
+ require File.dirname(__FILE__) / 'warning_shot'
2
+ require File.dirname(__FILE__) / 'template_generator'
3
+
4
+ # This is a factory class for creating WarningShot hash configurations.
5
+ # Configurations can be created by passing a hash or block to
6
+ # WarningShot::Config.create
7
+ # OR
8
+ # By calling WarningShot::Config.parse_args (for command line, uses ARGV)
9
+ #
10
+ # It also provies an interface for plugins to extend the CLI
11
+ # Config.cli => Provides access to add stuff to command line
12
+ # Config.cli_options => Provides a hash to store values into from within the OptionParser block
13
+ #
14
+ # The resolver class also provides functions of the same name that shortcut to WarningShot::Config
15
+ #
16
+ # @example
17
+ # class WarningShot::MyResolver
18
+ # cli("-s", "--someflag=VALUE", String, "Add some feature") do |value|
19
+ # options[:some_value] = value
20
+ # end
21
+ #
22
+ module WarningShot
23
+ module Config
24
+ attr_reader :configuration
25
+ PARSER = OptionParser.new
26
+
27
+ DEFAULTS = {
28
+ :pload => [],
29
+ :oload => [],
30
+ :environment => 'development',
31
+ :resolve => false,
32
+ :config_paths => ['.' / 'config' / 'warningshot', '~' / '.warningshot'],
33
+ :application => '.',
34
+ :log_path => '.' / 'log' / 'warningshot.log',
35
+ :log_level => :info,
36
+ :growl => false,
37
+ :verbose => false,
38
+ :colorize => true,
39
+ :resolvers => ['~' / '.warningshot' / '*.rb']
40
+ }.freeze
41
+
42
+ class << self
43
+
44
+ # Add command line flags to tail of CLI
45
+ # shortcut to WarningSHot::Config::PARSER.on_tail
46
+ #
47
+ # @see OptionParser
48
+ #
49
+ # @param *opts [Array]
50
+ #
51
+ # @param &block [Proc]
52
+ #
53
+ # @api public
54
+ def cli(*opts,&block)
55
+ PARSER.on_tail(*opts,&block)
56
+ end
57
+
58
+ # access to a hash for command line options use for Plugin to extend interface
59
+ #
60
+ # @return [Hash]
61
+ def cli_options
62
+ @@cli_options ||={}
63
+ @@cli_options
64
+ end
65
+
66
+ #
67
+ # Initialize a new WarningShot config
68
+ #
69
+ # @example
70
+ # Setting config with a hash
71
+ # conf = WarningShot::Config.create({:environment=>"staging",:chickens=>true})
72
+ #
73
+ # Setting config with a block
74
+ # conf = WarningShot::Config.create do |c|
75
+ # c[:environment] = "production"
76
+ # c[:cool_feature] = true
77
+ # end
78
+ #
79
+ # Just using default config
80
+ # conf = WarningShot::Config.create
81
+ #
82
+ # Using a hash and a block, block wins
83
+ # conf = WarningShot::Config.create({:environment=>"hash",:something=>true}) do |c|
84
+ # c[:environment] = "blk"
85
+ # c[:else] = true
86
+ # end
87
+ #
88
+ def create(config={})
89
+ opt_config = config
90
+ if block_given?
91
+ blk_config = {}
92
+ yield(blk_config)
93
+ opt_config = opt_config.merge(blk_config)
94
+ end
95
+ WarningShot::Config::DEFAULTS.clone.merge(opt_config)
96
+ end
97
+
98
+ def parse_args(argv = ARGV)
99
+ @@cli_options = {}
100
+ @@cli_options[:environment] = ENV["WARNING_SHOT_ENV"] if ENV["WARNING_SHOT_ENV"]
101
+
102
+ WarningShot::Config::PARSER.banner = WarningShot.header
103
+ WarningShot::Config::PARSER.banner += "\n"
104
+ WarningShot::Config::PARSER.banner += "Dependency Resolution Framework\n\n"
105
+ WarningShot::Config::PARSER.banner += "Usage: warningshot [options]"
106
+
107
+
108
+ WarningShot::Config::PARSER.separator "Standard Flags".center(80,'-')
109
+ WarningShot::Config::PARSER.on("-e=STRING", "--environment=STRING", String, "Environment to test in","Default: #{DEFAULTS[:environment]}") do |env|
110
+ @@cli_options[:environment] = env
111
+ end
112
+ WarningShot::Config::PARSER.on("--resolve","Resolve missing dependencies (probably need sudo)") do |resolve|
113
+ @@cli_options[:resolve] = resolve
114
+ end
115
+ WarningShot::Config::PARSER.on("-a=PATH","--app=PATH", String, "Path to application", "Default: #{DEFAULTS[:application]}") do |app|
116
+ @@cli_options[:application] = app
117
+ end
118
+ WarningShot::Config::PARSER.on("-c=PATH","--configs=PATH", String,"Path to config directories (':' seperated)","Default: #{DEFAULTS[:config_paths].join(':')}") do |config|
119
+ @@cli_options[:config_paths] = config.split(':')
120
+ end
121
+
122
+
123
+ WarningShot::Config::PARSER.separator "Resolver Loading Flags".center(80,'-')
124
+ WarningShot::Config::PARSER.on("-r=PATH","--resolvers=PATH", String,"Globs to add'l resolvers (':' seperated)","Default: #{DEFAULTS[:resolvers].join(':')}") do |config|
125
+ @@cli_options[:resolvers] = config.split(':')
126
+ end
127
+ WarningShot::Config::PARSER.on("--oload=LIST", String, "Only load specified resolvers (Command seperated)") do |oload|
128
+ @@cli_options[:oload] = oload.split(',')
129
+ WarningShot.only_load *@@cli_options[:oload]
130
+ end
131
+ WarningShot::Config::PARSER.on("--pload=LIST", String, "Load specified resolvers only, setting sequential priority (Command seperated)") do |pload|
132
+ @@cli_options[:pload] = pload.split(',')
133
+ WarningShot.only_load *@@cli_options[:pload]
134
+ end
135
+
136
+
137
+ WarningShot::Config::PARSER.separator "Output Flags".center(80,'-')
138
+ WarningShot::Config::PARSER.on("-l=LOG","--log=LOG", String, "Path to log file", "Default: #{DEFAULTS[:log_path]}") do |log_path|
139
+ @@cli_options[:log_path] = log_path
140
+ end
141
+ WarningShot::Config::PARSER.on("--loglevel=LEVEL",[:debug, :info, :warn, :error, :fatal], "Default: #{DEFAULTS[:log_level]}") do |log_level|
142
+ @@cli_options[:log_level] = log_level
143
+ end
144
+ WarningShot::Config::PARSER.on("-g", "--growl", "Output results via growl (Requires growlnotify)") do |growl|
145
+ @@cli_options[:growl] = growl
146
+ end
147
+ WarningShot::Config::PARSER.on("-p", "--[no-]prettycolors", "Colorize output") do |colorize|
148
+ @@cli_options[:colorize] = colorize
149
+ end
150
+ WarningShot::Config::PARSER.on("-v", "--verbose", "Output verbose information") do |verbose|
151
+ @@cli_options[:verbose] = verbose
152
+ end
153
+ WarningShot::Config::PARSER.on("--very-verbose", "Outputs debugging information, same as --loglevel=DEBUG") do |verbose|
154
+ @@cli_options[:verbose] = true
155
+ @@cli_options[:log_level] = :debug
156
+ end
157
+
158
+
159
+ WarningShot::Config::PARSER.separator "Prestaging Flags".center(80,'-')
160
+ WarningShot::Config::PARSER.on("--build-deps", "Installs gems that WarningShot resolvers depend on into standard RubyGems path (probably need sudo)") do |deps|
161
+ build_deps_config = WarningShot::Config.create
162
+ WarningShot.load_addl_resolvers build_deps_config[:resolvers]
163
+
164
+ warningshot_gem_recipe = []
165
+ Resolver.descendants(false).each do |klass|
166
+ klass.depends_on[:gem].each{ |gem_dep| warningshot_gem_recipe.push(gem_dep) }
167
+ end
168
+
169
+ gem_resolver = WarningShot::GemResolver.new build_deps_config, *warningshot_gem_recipe
170
+ gem_resolver.test!
171
+
172
+ if gem_resolver.failed.length == 0
173
+ puts 'WarningShot is A-OK!!!'
174
+ else
175
+ gem_resolver.resolve!
176
+ gem_resolver.resolved.each{|res_gem| puts "[SUCCESS]\t\t#{res_gem.name}" }
177
+
178
+ gem_resolver.unresolved.each{|unres_gem| puts "[FAILURE]\t\t#{unres_gem.name}" }
179
+ end
180
+
181
+ exit
182
+ end
183
+ WarningShot::Config::PARSER.on("--list-deps", "List all core libs and gems that each resolver is dependent on") do |deps|
184
+ puts WarningShot.header
185
+ puts "Resolvers' dependencies:"
186
+
187
+ Resolver.descendants(false).each do |klass|
188
+ puts "\n#{klass}"
189
+ puts " Core Lib Dependencies:"
190
+ klass.depends_on[:core].each do |core|
191
+ puts " [#{core[:installed] ? 'INSTALLED' : 'MISSING'}]\t\t#{core[:name]}"
192
+ end
193
+
194
+ puts " Gem Dependencies:"
195
+ klass.depends_on[:gem].each do |gem|
196
+ puts " [#{gem[:installed] ? 'INSTALLED' : 'MISSING'}]\t\t#{gem[:name]}"
197
+ end
198
+ end
199
+
200
+ exit
201
+ end
202
+
203
+
204
+ WarningShot::Config::PARSER.separator "Help, Info, & Etc. Flags".center(80,'-')
205
+ WarningShot::Config::PARSER.on("-t[PATH]","--templates[PATH]", String, "Generate template files", "Default: .") do |template_path|
206
+ template_path = @@cli_options[:config_paths].first if template_path.nil? || template_path.empty?
207
+ WarningShot::TemplateGenerator.create(template_path)
208
+ exit
209
+ end
210
+ WarningShot::Config::PARSER.on("--version", "Show version"){
211
+ WarningShot::Config::PARSER.parse!(argv)
212
+ conf = WarningShot::Config.create(@@cli_options)
213
+
214
+ WarningShot.load_app(conf[:application])
215
+ WarningShot.load_addl_resolvers(conf[:resolvers])
216
+
217
+ puts WarningShot.header
218
+ puts "Installed resolvers:"
219
+ Resolver.descendants(false).each { |klass|
220
+ puts "\n#{klass}"
221
+ puts " Tests: #{klass.tests.length}, Resolutions: #{klass.resolutions.length} [#{klass.resolutions.empty? ? 'irresolvable' : 'resolvable'}]"
222
+ puts " #{klass.description}"
223
+ }
224
+ exit
225
+ }
226
+ WarningShot::Config::PARSER.on("-h", "--help","Show this help message") { puts WarningShot::Config::PARSER; exit }
227
+ WarningShot::Config::PARSER.on("--debugger","Enable debugging") do
228
+ begin
229
+ require "ruby-debug"
230
+ Debugger.start
231
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
232
+ puts "Debugger enabled"
233
+ rescue LoadError => ex
234
+ puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
235
+ exit
236
+ end
237
+ end
238
+
239
+
240
+ WarningShot::Config::PARSER.separator "Resolver Specific Flags".center(80,'-')
241
+
242
+ WarningShot::Config::PARSER.parse!(argv)
243
+
244
+ @curr_config = @@cli_options.clone
245
+ @@cli_options = {}
246
+ return WarningShot::Config.create(@curr_config)
247
+ rescue OptionParser::InvalidOption, OptionParser::InvalidArgument,OptionParser::NeedlessArgument => op
248
+ puts op
249
+ puts WarningShot::Config::PARSER;
250
+ end
251
+
252
+ end #End self
253
+ end #End Config
254
+ end#End WarningShot
@@ -1,3 +1,8 @@
1
+ require File.dirname(__FILE__) / 'warning_shot'
2
+ require File.dirname(__FILE__) / 'resolver'
3
+ require File.dirname(__FILE__) / 'config'
4
+ require File.dirname(__FILE__) / 'logger'
5
+
1
6
  module WarningShot
2
7
  class DependencyResolver
3
8
 
@@ -8,13 +13,19 @@ module WarningShot
8
13
  @dependency_tree = {}
9
14
  @resolvers = []
10
15
 
11
- init_logger
16
+ self.init_logger
17
+ WarningShot.load_app(self[:application])
18
+ WarningShot.load_addl_resolvers(self[:resolvers])
12
19
 
13
20
  # Parsed yml files
14
21
  self.load_configs
15
22
  @dependency_tree.symbolize_keys!
16
23
  end
17
-
24
+
25
+ def [](k)
26
+ @config[k]
27
+ end
28
+
18
29
  # gets stats of all resolvers
19
30
  # @return [Hash]
20
31
  # :passed, :failed, :resolved, :unresolved
@@ -39,15 +50,15 @@ module WarningShot
39
50
  #
40
51
  # @api private
41
52
  def init_logger
42
- FileUtils.mkdir_p(File.dirname(File.expand_path(@config[:log_path]))) unless @config[:verbose]
53
+ FileUtils.mkdir_p(File.dirname(File.expand_path(self[:log_path]))) unless self[:verbose]
43
54
 
44
55
  @logger = Logger.new(
45
- @config[:verbose] ? STDOUT : @config[:log_path], 10, 1024000
56
+ self[:verbose] ? STDOUT : self[:log_path], 10, 1024000
46
57
  )
47
- _log_level = (@config[:log_level] || :debug).to_s.upcase
58
+ _log_level = (self[:log_level] || :info).to_s.upcase
48
59
 
49
60
  _formatter = WarningShot::LoggerFormatter.new
50
- _formatter.colorize = @config[:colorize]
61
+ _formatter.colorize = self[:colorize]
51
62
 
52
63
  @logger.formatter = _formatter
53
64
  @logger.level = Object.class_eval("Logger::#{_log_level}")
@@ -58,21 +69,26 @@ module WarningShot
58
69
  # @api private
59
70
  def run
60
71
  @logger.info "WarningShot v. #{WarningShot::VERSION}"
61
- @logger.info "Environment: #{WarningShot.environment}; Application: #{WarningShot.framework}"
72
+ @logger.info "Environment: #{self.environment}; Application: #{WarningShot.application_type}"
62
73
  @logger.info "On host: #{WarningShot.hostname}"
63
74
 
64
- WarningShot::Resolver.descendents.each do |klass|
75
+ WarningShot::Resolver.descendants.each do |klass|
76
+ next if klass.disabled?
77
+
65
78
  @logger.info "\n#{'-'*60}"
66
79
 
67
80
  branch = @dependency_tree[klass.branch.to_sym]
68
81
 
69
82
  if branch.nil?
70
- @logger.info "No config file was found for branch #{klass.branch}"
83
+ @logger.info "[SKIPPING] #{klass}, #{klass.branch}; No machine recipes was registered"
84
+ next
85
+ elsif branch.empty?
86
+ @logger.info "[SKIPPING] #{klass}, #{klass.branch}; No dependencies in machine recipe"
71
87
  next
72
88
  end
73
89
 
74
90
  klass.logger = @logger
75
- resolver = klass.new(*branch)
91
+ resolver = klass.new(@config,*branch)
76
92
 
77
93
  @resolvers << resolver
78
94
 
@@ -85,10 +101,10 @@ module WarningShot
85
101
 
86
102
  @logger.info "Passed: #{resolver.passed.size} / Failed: #{resolver.failed.size}"
87
103
 
88
- if WarningShot::Config.configuration[:resolve] && !klass.resolutions.empty?
104
+ if self[:resolve] && !klass.resolutions.empty?
89
105
  @logger.info "#{resolver.class}; branch: #{klass.branch} [RESOLVING]"
90
106
 
91
- klass.before_filters(:resolution).each{|p| p.call}
107
+ klass.before_filters(:resolution).each{|p| p.call}
92
108
  resolver.resolve!
93
109
  klass.after_filters(:resolution).each{|p| p.call}
94
110
 
@@ -105,10 +121,10 @@ module WarningShot
105
121
  #
106
122
  # @api protected
107
123
  def load_configs
108
- @config[:config_paths].each do |config_path|
124
+ self[:config_paths].each do |config_path|
109
125
  #Parse the global/running env configs out of the YAML files.
110
- Dir[config_path / WarningShot::ConfigExt].each do |config_file|
111
- # Use WarningShot::ConfigExt & regexp on extension to make supporting add'l
126
+ Dir[config_path / WarningShot::RecipeExt].each do |config_file|
127
+ # Use WarningShot::RecipeExt & regexp on extension to make supporting add'l
112
128
  # file types easier in the future
113
129
  case File.extname(config_file)
114
130
  when /.y(a)?ml/
@@ -132,8 +148,13 @@ module WarningShot
132
148
  def parse_yml(file)
133
149
  #if only on branch is specified in a yaml file it may not come back as an array
134
150
  branches = YAML::load(File.open(file,'r'))
135
- branches = [branches] unless branches.is_a? Array
136
151
 
152
+ if branches === false
153
+ @logger.error "Skipping malformed Yaml file: #{file}"
154
+ return
155
+ end
156
+
157
+ branches = [branches] unless branches.is_a? Array
137
158
  branches.each do |branch|
138
159
  branch_name = branch[:branch]
139
160
  dependency_tree[branch_name] ||= []
@@ -150,6 +171,6 @@ module WarningShot
150
171
  @dependency_tree[branch_name].delete(nil)
151
172
  end
152
173
  end
153
-
174
+
154
175
  end
155
176
  end
@@ -1,3 +1,5 @@
1
+ require File.dirname(__FILE__) / 'warning_shot'
2
+
1
3
  module WarningShot
2
4
  class Growl
3
5
 
@@ -1,3 +1,5 @@
1
+ require File.dirname(__FILE__) / 'warning_shot'
2
+
1
3
  module WarningShot
2
4
  class LoggerFormatter < Logger::Formatter
3
5
 
@@ -1,3 +1,5 @@
1
+ require File.dirname(__FILE__) / 'warning_shot'
2
+
1
3
  # API access for resolvers
2
4
  #
3
5
  # @example
@@ -10,46 +12,78 @@
10
12
  module WarningShot
11
13
  module Resolver
12
14
  module ClassMethods
13
- attr_reader :raw_cli_ext
14
15
 
15
- # extends command line interface
16
+ # creates a list of gems that the resolver is dependent on for different features
17
+ # The goal of this is that WarningShot will not need a bunch of libraries installed unless
18
+ # the end users needs that specific functionality. If a corelib/gem is missing the logger will
19
+ # receive warnings if a particular functionality that needs that library is enabled and its missing
20
+ # The missing GEMS can be installed with: warningshot --build-deps
21
+ # All resolvers' dependencies can be viewed with: warningshot --list-deps
22
+ #
23
+ # @param type [Symbol[:core|:gem]]
24
+ # the type of library it depends on, core lib or gem
25
+ #
26
+ # @param req_name [String]
27
+ # What would normally go in 'require'
28
+ #
29
+ # @param dep_opts [Hash]
30
+ # :disable [Boolean] Default: true
31
+ # Should the resolver be disabled if the gem is missing
32
+ # :unregister [Array[Symbol]]
33
+ # Test / Resolutions to unregister
34
+ # :name [String]
35
+ # Alternate name to use to install missing gem with warningshot --build-deps
36
+ # Example: require 'net/scp' would need gem install net-scp
37
+ # :version [String]
38
+ # The version to install
39
+ # :source [String]
40
+ # Alternate gem source
41
+ #
42
+ def add_dependency(type,req_name,dep_opts={})
43
+ require req_name
44
+ dep_opts[:installed] = true
45
+ rescue LoadError => ex
46
+ self.disable! unless dep_opts[:disable] === false
47
+ dep_opts[:installed] = false
48
+ ensure
49
+ @dependent_libs ||= {:core => [], :gem => []}
50
+
51
+ #if an alternate name isn't specified refer to it by the req_name
52
+ dep_opts[:name] ||= req_name
53
+ @dependent_libs[type].push dep_opts
54
+ end
55
+
56
+ # list the gems the resolver relies on
57
+ #
58
+ # @return [Hash]
59
+ def depends_on
60
+ @dependent_libs ||= {:core => [], :gem => []}
61
+ end
62
+
63
+ # provides shortcut to WarningShot::Config.cli_options
64
+ #
65
+ # @see WarningShot::Config
66
+ #
67
+ # @return [Hash]
68
+ #
69
+ def options
70
+ WarningShot::Config.cli_options
71
+ end
72
+
73
+ # provides shortcut to WarningShot::Config.cli
74
+ #
75
+ # @see OptionParser
76
+ # @see WarningShot::Config
16
77
  #
17
- # @param opts [Hash]
18
- # Keys and example values
19
- # :short => "-s",
20
- # :long => "--longflag",
21
- # :default => "my_value",
22
- # :description => "Command line description",
23
- # :name => "keyname", #required
24
- # :type => String #[:list, :of, :available, :values]
25
- # :default_desc => "Default: my_value"
78
+ # @param *opts [Array]
79
+ #
80
+ # @param &block [Proc]
81
+ #
26
82
  # @api public
27
- def cli(opts)
28
- @raw_cli_ext ||= []
29
- #Do not extend the interface if the class is being
83
+ def cli(*opts,&block)
30
84
  return if self.disabled?
31
85
 
32
- ##A keyname for the option is required
33
- return if opts[:name].nil?
34
- @raw_cli_ext << opts
35
-
36
- clean_opts = [
37
- opts[:short],
38
- opts[:long],
39
- opts[:type],
40
- opts[:description],
41
- opts[:default_desc]
42
- ]
43
- clean_opts.delete(nil)
44
-
45
- #Set the default value if it was given
46
- opt_name = opts[:name].intern
47
- WarningShot::Config[opt_name] = opts[:default]
48
-
49
- WarningShot.parser.on_tail(*clean_opts) do |val|
50
- WarningShot::Config[opt_name] = val
51
- end
52
-
86
+ WarningShot::Config.cli(*opts, &block)
53
87
  end
54
88
 
55
89
  # Setter/Getter for resolver branch,
@@ -128,6 +162,23 @@ module WarningShot
128
162
  @disabled = true
129
163
  end
130
164
 
165
+ # enables a resolver (enabled by default)
166
+ #
167
+ # @example
168
+ # class MyResolver
169
+ # include WarningShot::Resolver
170
+ # disable!
171
+ # end
172
+ #
173
+ # # Maybe you only want to enable it under some conditions
174
+ # MyResolver.enabled! if my_merb_or_rails_env == 'production'
175
+ # MyResolver.enabled! if @pickles.count == @chickens.count
176
+ #
177
+ # @api public
178
+ def enable!
179
+ @disabled = false
180
+ end
181
+
131
182
  # Determines if resolver is disabled
132
183
  #
133
184
  # @return [Boolean]
@@ -164,7 +215,7 @@ module WarningShot
164
215
  # How to cast the data to an object
165
216
  #
166
217
  # @api public
167
- def cast(klass=nil,&block)
218
+ def typecast(klass=nil,&block)
168
219
  if klass.nil?
169
220
  klass = :default
170
221
  else
@@ -172,8 +223,8 @@ module WarningShot
172
223
  end
173
224
  (@yaml_to_object_methods||={})[klass] = block
174
225
  end
175
-
176
- # calls the block defined by Resolver#cast to convert
226
+
227
+ # calls the block defined by Resolver#typecast to convert
177
228
  # the yaml data to an object
178
229
  #
179
230
  # @param data [~YAML::load]
@@ -240,8 +291,7 @@ module WarningShot
240
291
  #
241
292
  # register :resolution, :if => lambda{|dependency|
242
293
  # #This will determin if resolution should be attempted
243
- # # this would only resolve in production
244
- # WarningShot.environment == 'production'
294
+ # my_special_instance == true
245
295
  # } do |dependency|
246
296
  # my_method_that_would_resolve dependency
247
297
  # end
@@ -302,6 +352,14 @@ module WarningShot
302
352
  end
303
353
  end
304
354
 
355
+ # removes all test/resolutions from a resolver
356
+ #
357
+ # @api public
358
+ def flush!
359
+ flush_tests!
360
+ flush_resolutions!
361
+ end
362
+
305
363
  # Removes all tests from a resolver
306
364
  #
307
365
  # @api public
@@ -379,7 +437,7 @@ module WarningShot
379
437
  #
380
438
  # @api private
381
439
  def test!
382
- dependencies.each do |dep|
440
+ dependencies.each do |dep|
383
441
  self.class.tests.each{ |test_meta|
384
442
  dep.met = process_block :test, dep, test_meta
385
443
  break if dep.met
@@ -392,10 +450,12 @@ module WarningShot
392
450
  # @api private
393
451
  def resolve!
394
452
  dependencies.each do |dep|
395
- self.class.resolutions.each{ |resolution_meta|
396
- dep.resolved = process_block :resolution, dep, resolution_meta
397
- break if dep.resolved
398
- }
453
+ unless dep.met
454
+ self.class.resolutions.each{ |resolution_meta|
455
+ dep.resolved = process_block :resolution, dep, resolution_meta
456
+ break if dep.resolved
457
+ }
458
+ end
399
459
  end
400
460
  end
401
461
 
@@ -407,11 +467,7 @@ module WarningShot
407
467
  # @api private
408
468
  def unresolved
409
469
  dependencies.inject([]){ |list,dep|
410
- if !dep.met && !dep.resolved
411
- list << dep
412
- else
413
- list
414
- end
470
+ (!dep.met && !dep.resolved) ? (list << dep) : (list)
415
471
  }
416
472
  end
417
473
 
@@ -423,25 +479,18 @@ module WarningShot
423
479
  # @api private
424
480
  def failed
425
481
  dependencies.inject([]){ |list,dep|
426
- unless dep.met
427
- list << dep
428
- else
429
- list
430
- end
482
+ dep.met ? (list) : (list << dep)
431
483
  }
432
484
  end
433
485
 
434
486
  # list of successful dependencies
435
487
  #
436
488
  # @return [Array<Objects>]
489
+ #
437
490
  # @api private
438
491
  def passed
439
492
  dependencies.inject([]){ |list,dep|
440
- if dep.met
441
- list << dep
442
- else
443
- list
444
- end
493
+ dep.met ? (list << dep) : (list)
445
494
  }
446
495
  end
447
496
 
@@ -453,15 +502,15 @@ module WarningShot
453
502
  # @api private
454
503
  def resolved
455
504
  dependencies.inject([]){ |list,dep|
456
- if(!dep.met && dep.resolved)
457
- list << dep
458
- else
459
- list
460
- end
505
+ (!dep.met && dep.resolved) ? (list << dep) : (list)
461
506
  }
462
507
  end
463
508
 
464
- # loads up instance variables for new test
509
+ # setups up a resolver with config and dependencies
510
+ #
511
+ # @param config [WarningShot::Config]
512
+ # Configuration to use
513
+ #
465
514
  # @param *deps [Array]
466
515
  # Dependencies from YAML file
467
516
  #
@@ -472,8 +521,10 @@ module WarningShot
472
521
  # resolved [Boolean] Was teh dependency resolved
473
522
  #
474
523
  # @api semi-public
475
- def initialize(*deps)
524
+ def initialize(config,*deps)
525
+ @config = config
476
526
  @dependencies = Set.new
527
+
477
528
  deps.each do |dep|
478
529
  # Cast YAML data as described in resolver.
479
530
  dep = self.class.yaml_to_object(dep)
@@ -482,10 +533,7 @@ module WarningShot
482
533
  @dependencies.add dep
483
534
  end
484
535
  end
485
-
486
- attr_accessor :logger
487
- attr_accessor :dependencies
488
-
536
+
489
537
  protected
490
538
  # processes a test or resolution block
491
539
  #
@@ -494,7 +542,6 @@ module WarningShot
494
542
  #
495
543
  # @param dep <Hash>
496
544
  # Dependency parsed from yaml configs (Currently Hash)
497
- # TODO; once Dependencies are an object besides Hash, this may need to be changed
498
545
  #
499
546
  # @param block_info <Hash>
500
547
  # The block details and proc
@@ -502,33 +549,72 @@ module WarningShot
502
549
  # @return <Boolean>
503
550
  # Was the block successful; meaning conditions passed and block returned true
504
551
  #
552
+ # @note
553
+ # If anyone knows a better way then doing the arity check go for it. I'd
554
+ # like the register api to 'just work' and not have the writer worry about
555
+ # a dependency or a configuration unless they need it. I know that a Proc
556
+ # works no matter how many arguments are passed to it, but a lambda checks
557
+ # to make sure its the correct number, and apparently "do;end;" and "{ }"
558
+ # check for the number of arguments.
559
+ #
560
+ # Also note for this, :unless, :if and the block all need a different set of
561
+ # params because someone may have registered a :if condition that has a different
562
+ # signature than the test/resolution block
563
+ #
564
+ # register(:test,:if=>lambda{WarningShot.hostname=="boogertron"}) do |dep,config|
565
+ # puts "A test that needs dep & config"
566
+ # end
567
+ #
505
568
  # @api private
506
569
  def process_block(type, dep, block_info)
570
+ block_params = case block_info[type].arity
571
+ when 1
572
+ dep
573
+ when 2
574
+ [dep,self.config]
575
+ end
576
+
577
+ if_params = case
578
+ when 1
579
+ dep
580
+ when 2
581
+ [dep,self.config]
582
+ end if block_info[:if]
583
+
584
+ unless_params = case
585
+ when 1
586
+ dep
587
+ when 2
588
+ [dep,self.config]
589
+ end if block_info[:unless]
590
+
507
591
  if !block_info[:if] && !block_info[:unless]
508
- # no condition, run block
509
- return block_info[type].call(dep)
510
- elsif block_info[:if] && block_info[:if].call(dep)
511
- #if Condition given and it applies, run block
512
- return block_info[type].call(dep)
513
- elsif block_info[:unless] && !block_info[:unless].call(dep)
514
- #unless Condition given and it applies, run block
515
- return block_info[type].call(dep)
592
+ #if no conditions, run block
593
+ return block_info[type].call(block_params)
594
+ elsif block_info[:if] && block_info[:if].call(if_params)
595
+ #elsif 'if' Condition given and it applies, run block
596
+ return block_info[type].call(block_params)
597
+ elsif block_info[:unless] && !block_info[:unless].call(unless_params)
598
+ #elsif 'unless' Condition given and it applies, run block
599
+ return block_info[type].call(block_params)
516
600
  end
517
601
 
518
602
  return false
519
603
  end
520
604
  end
521
605
 
522
- @@descendents = []
523
- def self.descendents
524
- #Filter out descendents that are disabled
525
- temp_descendents = []
526
- @@descendents.each do |klass|
527
- temp_descendents.push(klass) unless klass.disabled?
528
- end
606
+ @@descendants = []
607
+ def self.descendants(filter_disabled=true)
608
+ #Filter out descendants that are disabled
609
+ temp_descendants = []
610
+
611
+
612
+ @@descendants.each{ |klass|
613
+ temp_descendants.push(klass) unless filter_disabled && klass.disabled?
614
+ }
529
615
 
530
616
  #Sort by order
531
- temp_descendents.sort_by{|desc| desc.order}
617
+ temp_descendants.sort_by{|desc| desc.order}
532
618
  end
533
619
 
534
620
 
@@ -536,7 +622,9 @@ module WarningShot
536
622
  def self.included(subclass)
537
623
  subclass.extend ClassMethods
538
624
  subclass.send :include, InstanceMethods
539
- @@descendents.push subclass
625
+ subclass.send :attr_reader, :config
626
+ subclass.send :attr_accessor, :dependencies
627
+ @@descendants.push subclass
540
628
  end
541
629
  end
542
630
  end