Sutto-perennial 0.2.4.1 → 0.2.4.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/perennial.rb CHANGED
@@ -9,12 +9,12 @@ require 'perennial/exceptions'
9
9
 
10
10
  module Perennial
11
11
 
12
- VERSION = "0.2.4.1"
12
+ VERSION = "0.2.4.5"
13
13
 
14
14
  has_library :dispatchable, :hookable, :loader, :logger, :nash,
15
15
  :loggable, :manifest, :settings, :argument_parser,
16
16
  :option_parser, :application, :generator, :daemon,
17
- :delegateable
17
+ :delegateable, :reloading
18
18
 
19
19
  def self.included(parent)
20
20
  parent.extend(Manifest::Mixin)
@@ -53,8 +53,8 @@ module Perennial
53
53
  @banners = {}
54
54
  end
55
55
 
56
- def option(name, description = nil)
57
- option_parser.add(name, description) { |v| @command_options[name] = v }
56
+ def option(name, description = nil, opts = {})
57
+ option_parser.add(name, description, opts) { |v| @command_options[name] = v }
58
58
  end
59
59
 
60
60
  def add_default_options!
@@ -21,6 +21,10 @@ module Perennial
21
21
  @@handler_mapping ||= Hash.new { |h,k| h[k] = [] }
22
22
  end
23
23
 
24
+ def self.reloading_mapping
25
+ @@reloading_mapping ||= Hash.new { |h,k| h[k] = [] }
26
+ end
27
+
24
28
  def self.included(parent)
25
29
  parent.class_eval do
26
30
  include InstanceMethods
@@ -125,6 +129,18 @@ module Perennial
125
129
  end
126
130
  end
127
131
 
132
+ def reloading!
133
+ handlers = Dispatchable.handler_mapping.delete(self)
134
+ Dispatchable.reloading_mapping[self.name] = handlers
135
+ end
136
+
137
+ def reloaded!
138
+ if Dispatchable.reloading_mapping.has_key?(self.name)
139
+ handlers = Dispatchable.reloading_mapping.delete(self.name)
140
+ handlers.each { |h| register_handler(h) }
141
+ end
142
+ end
143
+
128
144
  end
129
145
 
130
146
  end
@@ -73,6 +73,7 @@ module Perennial
73
73
  handler_directory = Settings.root / "handlers"
74
74
  if File.directory?(handler_directory)
75
75
  Dir[handler_directory / "**" / "*.rb"].each do |handler|
76
+ Perennial::Reloading.watch(handler, handler_directory)
76
77
  require handler
77
78
  end
78
79
  end
@@ -9,7 +9,7 @@ module Perennial
9
9
  contents = YAML.load_file(path)
10
10
  end
11
11
  if contents.is_a?(Hash)
12
- contents.to_hash
12
+ contents.to_nash
13
13
  else
14
14
  new(:data => contents).normalized
15
15
  end
@@ -52,9 +52,9 @@ module Perennial
52
52
  def add_defaults!
53
53
  return if defined?(@defaults_added) && @defaults_added
54
54
  logger_levels = Logger::LEVELS.keys.map { |k| k.to_s }
55
- add(:daemon, 'Runs this application as a daemon') { Settings.daemon = true }
56
- add(:verbose, 'Runs this application verbosely, writing to STDOUT') { Settings.verbose = true }
57
- add(:log_level, "Sets this applications log level, one of: #{logger_levels.join(", ")}") do |level|
55
+ add(:daemon, 'Runs this application as a daemon', :shortcut => "d") { Settings.daemon = true }
56
+ add(:verbose, 'Runs this application verbosely, writing to STDOUT', :shortcut => "v") { Settings.verbose = true }
57
+ add(:log_level, "Sets this applications log level, one of: #{logger_levels.join(", ")}", :shortcut => "l") do |level|
58
58
  if logger_levels.include?(level)
59
59
  Settings.log_level = level.to_sym
60
60
  else
@@ -0,0 +1,45 @@
1
+ module Perennial
2
+ class Reloading
3
+
4
+ cattr_accessor :mapping, :mtimes
5
+ self.mapping = {}
6
+ self.mtimes = {}
7
+
8
+ def self.watch(file, relative_to = File.dirname(file))
9
+ file = File.expand_path(file)
10
+ raise ArgumentError, "You must provide the path to a file" unless File.file?(file)
11
+ relative = file.gsub(/^#{File.expand_path(relative_to)}\//, '')
12
+ name = relative.gsub(/\.rb$/, '').split("/").map { |part|part.camelize }.join("::")
13
+ self.mapping[name] = file
14
+ self.mtimes[file] = File.mtime(file)
15
+ end
16
+
17
+ def self.reload!
18
+ self.mapping.each_pair do |constant, file|
19
+ next unless File.mtime(file) > self.mtimes[file]
20
+ begin
21
+ # Get a relative name and namespace
22
+ parts = constant.split("::")
23
+ name = parts.pop
24
+ ns = parts.inject(Object) { |a, c| a.const_get(c) }
25
+ # Notify object pre-reload.
26
+ final = ns.const_get(name)
27
+ final.reloading! if final.respond_to?(:reloading!)
28
+ final = nil
29
+ # Remove the constant
30
+ ns.send(:remove_const, name)
31
+ load(file)
32
+ # Notify the object it was reloaded...
33
+ final = ns.const_get(name)
34
+ final.reloaded! if final.respond_to?(:reloaded!)
35
+ # Finally, update the mtime
36
+ self.mtimes[file] = File.mtime(file)
37
+ rescue Exception => e
38
+ logger.fatal "Exception reloading #{file} (for #{constant})"
39
+ Perennial::ExceptionTracker.log(e)
40
+ end
41
+ end
42
+ end
43
+
44
+ end
45
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Sutto-perennial
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4.1
4
+ version: 0.2.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darcy Laycock
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-11 00:00:00 -07:00
12
+ date: 2009-09-16 00:00:00 -07:00
13
13
  default_executable: perennial
14
14
  dependencies: []
15
15
 
@@ -55,6 +55,7 @@ files:
55
55
  - lib/perennial/manifest.rb
56
56
  - lib/perennial/nash.rb
57
57
  - lib/perennial/option_parser.rb
58
+ - lib/perennial/reloading.rb
58
59
  - lib/perennial/settings.rb
59
60
  - lib/perennial.rb
60
61
  - test/delegateable_test.rb
@@ -74,6 +75,7 @@ files:
74
75
  - templates/test_helper.erb
75
76
  has_rdoc: false
76
77
  homepage: http://sutto.net/
78
+ licenses:
77
79
  post_install_message:
78
80
  rdoc_options: []
79
81
 
@@ -94,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
96
  requirements: []
95
97
 
96
98
  rubyforge_project:
97
- rubygems_version: 1.2.0
99
+ rubygems_version: 1.3.5
98
100
  signing_key:
99
101
  specification_version: 3
100
102
  summary: A simple (generally event-oriented) application library for Ruby