warningshot 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
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