madvertise-ext 0.2.2 → 0.3.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/.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