madvertise-ext 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use --create ruby-1.9.3-p125@madvertise-ext
1
+ rvm use --create ruby-1.9.3-p327@madvertise-ext
@@ -0,0 +1,23 @@
1
+ class Array
2
+
3
+ def pick(n=1)
4
+ Array.new(n) { self[Kernel::rand(size)-1] }
5
+ end
6
+
7
+ def pick_one
8
+ self[Kernel::rand(size)-1]
9
+ end
10
+
11
+ def to_h(&block)
12
+ Hash[*self.map { |v| [v, block.call(v)] }.flatten]
13
+ end
14
+
15
+ def / parts
16
+ inject([[]]) do |ary, x|
17
+ ary << [] if [*ary.last].nitems == length / parts
18
+ ary.last << x
19
+ ary
20
+ end
21
+ end
22
+
23
+ end
@@ -1,5 +1,8 @@
1
1
  require 'yaml'
2
+ require 'set'
3
+
2
4
  require 'madvertise/ext/hash'
5
+ require 'madvertise/ext/environment'
3
6
 
4
7
  ##
5
8
  # A {Configuration} consists of one or more Sections. A section is a hash-like
@@ -12,14 +15,24 @@ require 'madvertise/ext/hash'
12
15
  # => 1
13
16
  #
14
17
  class Section < Hash
18
+
15
19
  class << self
16
20
 
21
+ # How to handle nil values in the configuration?
22
+ #
23
+ # Possible values are:
24
+ # - :nil, nil (return nil)
25
+ # - :raise (raise an exception)
26
+ # - :section (return a NilSection which can be chained)
27
+ #
28
+ attr_accessor :nil_action
29
+
17
30
  # Create a new section from the given hash-like object.
18
31
  #
19
32
  # @param [Hash] hsh The hash to convert into a section.
20
33
  # @return [Section] The new {Section} object.
21
34
  def from_hash(hsh)
22
- result = new.tap do |result|
35
+ new.tap do |result|
23
36
  hsh.each do |key, value|
24
37
  result[key.to_sym] = from_value(value)
25
38
  end
@@ -42,28 +55,7 @@ class Section < Hash
42
55
  value
43
56
  end
44
57
  end
45
- end
46
58
 
47
- # Mixin a configuration snippet into the current section.
48
- #
49
- # @param [Hash, String] value A hash to merge into the current
50
- # configuration. If a string is given a filename
51
- # is assumed and the given file is expected to
52
- # contain a YAML hash.
53
- # @return [void]
54
- def mixin(value)
55
- unless value.is_a?(Hash)
56
- value = Section.from_hash(YAML.load(File.read(value)))
57
- end
58
-
59
- self.deep_merge!(value[:default]) if value.has_key?(:default)
60
- self.deep_merge!(value[:generic]) if value.has_key?(:generic)
61
-
62
- if value.has_key?(@mode)
63
- self.deep_merge!(value[@mode])
64
- else
65
- self.deep_merge!(value)
66
- end
67
59
  end
68
60
 
69
61
  # Build the call chain including NilSections.
@@ -75,7 +67,20 @@ class Section < Hash
75
67
  else
76
68
  value = self[name]
77
69
  value = value.call if value.is_a?(Proc)
78
- value = NilSection.new if value.nil?
70
+
71
+ if value.nil?
72
+ case self.class.nil_action
73
+ when :nil, nil
74
+ # do nothing
75
+ when :raise
76
+ raise "value is nil for key #{name}"
77
+ when :section
78
+ value = NilSection.new if value.nil?
79
+ else
80
+ raise "unknown nil handling: #{self.class.nil_action}"
81
+ end
82
+ end
83
+
79
84
  self[name] = value
80
85
  end
81
86
  end
@@ -92,8 +97,9 @@ class Configuration < Section
92
97
  # @param [Symbol] mode The mode to load from the configurtion file
93
98
  # (production, development, etc)
94
99
  # @yield [config] The new configuration object.
95
- def initialize(mode = :development)
96
- @mode = mode
100
+ def initialize
101
+ @mixins = Set.new
102
+ @callbacks = []
97
103
  yield self if block_given?
98
104
  end
99
105
 
@@ -110,25 +116,52 @@ class Configuration < Section
110
116
  end
111
117
  end
112
118
 
113
- ##
114
- # The {Helpers} module can be included in all classes that wish to load
115
- # configuration file(s). In order to load custom configuration files the
116
- # including class needs to set the +@config_file+ instance variable.
119
+ # Mixin a configuration snippet into the current section.
117
120
  #
118
- module Helpers
121
+ # @param [Hash, String] value A hash to merge into the current
122
+ # configuration. If a string is given a filename
123
+ # is assumed and the given file is expected to
124
+ # contain a YAML hash.
125
+ # @return [void]
126
+ def mixin(value)
127
+ if value.is_a?(String)
128
+ @mixins << value
129
+ value = YAML.load(File.read(value))
130
+ end
119
131
 
120
- # Load the configuration. The default configuration is located at
121
- # +lib/ganymed/config.yml+ inside the Ganymed source tree.
122
- #
123
- # @return [Configuration] The configuration object. See madvertise-ext gem
124
- # for details.
125
- def config
126
- @config ||= Configuration.new(Env.mode) do |config|
127
- config.mixin(@default_config_file) if @default_config_file
128
- config.mixin(@config_file) if @config_file
129
- end
132
+ value = Section.from_hash(value)
133
+
134
+ self.deep_merge!(value[:default]) if value.has_key?(:default)
135
+ self.deep_merge!(value[:generic]) if value.has_key?(:generic)
136
+
137
+ if value.has_key?(Env.to_sym)
138
+ self.deep_merge!(value[Env.to_sym])
139
+ else
140
+ self.deep_merge!(value)
141
+ end
142
+
143
+ @callbacks.each do |callback|
144
+ callback.call
130
145
  end
131
146
  end
147
+
148
+ # Reload all mixins.
149
+ #
150
+ # @return [void]
151
+ def reload!
152
+ self.clear
153
+ @mixins.each do |file|
154
+ self.mixin(file)
155
+ end
156
+ end
157
+
158
+ # Register a callback for config mixins.
159
+ #
160
+ # @return [void]
161
+ def callback(&block)
162
+ @callbacks << block
163
+ end
164
+
132
165
  end
133
166
 
134
167
  ##
@@ -12,9 +12,20 @@ class Hash
12
12
  end
13
13
  end
14
14
 
15
- # Recursively merge and replace +other_hash+ into +self.
15
+ # Recursively merge and replace +other_hash+ into +self+.
16
16
  def deep_merge!(other_hash)
17
17
  replace(deep_merge(other_hash))
18
18
  end
19
19
 
20
+ # accumulate existing keys from +other_hash+ into +self+.
21
+ def delta_merge!(other_hash)
22
+ other_hash.each do |k,v|
23
+ if self.has_key?(k)
24
+ self[k] += v
25
+ else
26
+ self[k] = v
27
+ end
28
+ end
29
+ end
30
+
20
31
  end
@@ -1,40 +1,26 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
1
+ # encoding: utf-8
2
+
2
3
  require 'madvertise/ext/environment'
3
4
  require 'madvertise-logging'
4
5
 
5
- ##
6
- # The {Logging} module provides a global container for the logger object.
7
- #
8
- module Logging
9
- mattr_accessor :logger
10
- self.logger = nil
6
+ def init_logger(progname=$0, filename=nil)
7
+ progname = File.basename(progname)
8
+ filename ||= "#{Env.mode}.log"
11
9
 
12
- # @private
13
- def self.create_logger
14
- if Env.prod?
15
- Madvertise::Logging::ImprovedLogger.new(:syslog, $0)
16
- else
17
- Madvertise::Logging::ImprovedLogger.new(STDERR, $0)
18
- end.tap do |logger|
19
- logger.level = :info
20
- end
10
+ MultiLogger.new.tap do |logger|
11
+ init_multi_logger(logger, progname, filename)
21
12
  end
13
+ end
22
14
 
23
- ##
24
- # The {Logging::Helpers} module is mixed into the Object class to make the
25
- # logger available to every object in the system.
26
- #
27
- module Helpers
28
-
29
- # Retreive and possibly create the global logger object.
30
- #
31
- # @return [Logger] The logger object.
32
- def log
33
- ::Logging.logger ||= ::Logging.create_logger
34
- end
15
+ def init_multi_logger(logger, progname=$0, filename=nil)
16
+ if Env.dev? or Env.test?
17
+ logger.attach(ImprovedLogger.new(STDERR, progname))
18
+ else
19
+ logger.attach(ImprovedLogger.new(:syslog, progname))
35
20
  end
36
- end
37
21
 
38
- class ::Object
39
- include ::Logging::Helpers
22
+ # default log level
23
+ logger.level = Logger::INFO
40
24
  end
25
+
26
+ $log = init_logger
@@ -0,0 +1,5 @@
1
+ class NilClass
2
+ def empty?
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ class String
2
+ alias each each_line
3
+ end
@@ -1,6 +1,6 @@
1
1
  # @private
2
2
  module Madvertise
3
3
  module Ext
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
6
6
  end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ require 'madvertise/ext/environment'
4
+ require 'mixlib/cli'
5
+ require 'servolux'
6
+
7
+ module Servolux
8
+ class BaseCLI
9
+ include Mixlib::CLI
10
+
11
+ def self.inherited(subclass)
12
+ subclass.option :environment,
13
+ :short => '-e ENVIRONMENT',
14
+ :long => '--environment ENVIRONMENT',
15
+ :description => "Set the daemon environment",
16
+ :default => "development",
17
+ :proc => ->(value) { Env.set(value) }
18
+
19
+ subclass.option :debug,
20
+ :short => '-D',
21
+ :long => '--debug',
22
+ :description => "Enable debug output",
23
+ :boolean => true,
24
+ :default => false
25
+
26
+ subclass.option :help,
27
+ :short => '-h',
28
+ :long => '--help',
29
+ :description => "Show this message",
30
+ :on => :tail,
31
+ :boolean => true,
32
+ :show_options => true,
33
+ :exit => 0
34
+ end
35
+
36
+ def self.parse_options
37
+ new.tap do |cli|
38
+ cli.parse_options
39
+ end.config
40
+ end
41
+ end
42
+
43
+ class CLI < BaseCLI
44
+ end
45
+
46
+ class DaemonCLI < BaseCLI
47
+ option :name,
48
+ :short => '-n NAME',
49
+ :long => '--name NAME',
50
+ :description => 'Process name',
51
+ :default => $0,
52
+ :proc => ->(value) { $0 = value }
53
+
54
+ option :pidfile,
55
+ :short => '-p PIDFILE',
56
+ :long => '--pidfile PIDFILE',
57
+ :description => "The daemon pidfile",
58
+ :default => "#{$0}.pid"
59
+
60
+ option :daemonize,
61
+ :short => '-d',
62
+ :long => '--daemonize',
63
+ :description => "Daemonize the server process",
64
+ :boolean => true,
65
+ :default => false
66
+
67
+ option :kill,
68
+ :short => '-k',
69
+ :long => '--kill',
70
+ :description => "Kill the currently running daemon instance",
71
+ :boolean => true
72
+ end
73
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require 'madvertise/ext/logging'
4
+ require 'servolux'
5
+ require 'servolux/cli'
6
+
7
+ module Servolux
8
+ def self.init_config(cli_class)
9
+ config = cli_class.parse_options
10
+
11
+ # CLI.parse_options may have changed $0
12
+ # so we reload the logger for good measure
13
+ $log = init_logger
14
+ $log.level = config[:debug] ? :debug : :info
15
+
16
+ return config
17
+ end
18
+
19
+ def self.wrap(server_class)
20
+ config = self.init_config(Servolux::CLI)
21
+ server_class.new(config).run
22
+ rescue => e
23
+ $log.exception(e)
24
+ raise e
25
+ end
26
+
27
+ def self.wrap_daemon(server_class)
28
+ config = self.init_config(Servolux::DaemonCLI)
29
+
30
+ server = server_class.new(config[:name], config.merge({
31
+ interval: 1,
32
+ logger: $log,
33
+ pid_file: config[:pidfile]
34
+ }))
35
+
36
+ if config[:daemonize] or config[:kill]
37
+ daemon = Servolux::Daemon.new(:server => server)
38
+
39
+ if config[:kill]
40
+ daemon.shutdown
41
+ else
42
+ daemon.startup
43
+ end
44
+ else
45
+ server.startup
46
+ end
47
+ rescue => e
48
+ $log.exception(e)
49
+ raise e
50
+ end
51
+ end
@@ -11,6 +11,8 @@ Gem::Specification.new do |gem|
11
11
  gem.homepage = "https://github.com/madvertise/ext"
12
12
 
13
13
  gem.add_dependency "madvertise-logging"
14
+ gem.add_dependency "mixlib-cli"
15
+ gem.add_dependency "servolux"
14
16
 
15
17
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
18
  gem.files = `git ls-files`.split("\n")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madvertise-ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-04 00:00:00.000000000 Z
12
+ date: 2013-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: madvertise-logging
16
- requirement: &20013940 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,44 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *20013940
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mixlib-cli
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: servolux
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
25
62
  description: Ruby extensions
26
63
  email:
27
64
  - benedikt.boehm@madvertise.com
@@ -37,14 +74,19 @@ files:
37
74
  - LICENSE
38
75
  - README.md
39
76
  - Rakefile
77
+ - lib/madvertise/ext/array.rb
40
78
  - lib/madvertise/ext/config.rb
41
79
  - lib/madvertise/ext/enumerable.rb
42
80
  - lib/madvertise/ext/environment.rb
43
81
  - lib/madvertise/ext/hash.rb
44
82
  - lib/madvertise/ext/logging.rb
45
83
  - lib/madvertise/ext/mask.reek
84
+ - lib/madvertise/ext/nil.rb
85
+ - lib/madvertise/ext/string.rb
46
86
  - lib/madvertise/ext/transaction_id.rb
47
87
  - lib/madvertise/ext/version.rb
88
+ - lib/servolux/cli.rb
89
+ - lib/servolux/wrapper.rb
48
90
  - madvertise-ext.gemspec
49
91
  - spec/enumerable_spec.rb
50
92
  - spec/spec.opts
@@ -66,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
108
  version: '0'
67
109
  segments:
68
110
  - 0
69
- hash: 2902116166702293423
111
+ hash: -2076914703053798103
70
112
  required_rubygems_version: !ruby/object:Gem::Requirement
71
113
  none: false
72
114
  requirements:
@@ -75,10 +117,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
117
  version: '0'
76
118
  segments:
77
119
  - 0
78
- hash: 2902116166702293423
120
+ hash: -2076914703053798103
79
121
  requirements: []
80
122
  rubyforge_project:
81
- rubygems_version: 1.8.17
123
+ rubygems_version: 1.8.24
82
124
  signing_key:
83
125
  specification_version: 3
84
126
  summary: Ruby extensions