easy_app_helper 1.0.2 → 1.0.3
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.
- checksums.yaml +4 -4
- data/.gitignore +47 -47
- data/Gemfile +4 -4
- data/LICENSE.txt +22 -22
- data/README.md +498 -498
- data/Rakefile +1 -1
- data/easy_app_helper.gemspec +26 -26
- data/lib/easy_app_helper/core/base.rb +141 -128
- data/lib/easy_app_helper/core/config.rb +203 -203
- data/lib/easy_app_helper/core/logger.rb +111 -103
- data/lib/easy_app_helper/core/merge_policies.rb +37 -37
- data/lib/easy_app_helper/core/places.rb +51 -51
- data/lib/easy_app_helper/module_manager.rb +67 -60
- data/lib/easy_app_helper/version.rb +10 -10
- data/lib/easy_app_helper.rb +20 -20
- data/test/test.yml +7 -7
- data/test/test2_app.rb +33 -33
- data/test/test3_app.rb +90 -90
- data/test/test4_app.rb +35 -35
- data/test/test_app.rb +55 -55
- metadata +2 -3
@@ -1,203 +1,203 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
require 'yaml'
|
9
|
-
# This is the class that will handle the configuration.
|
10
|
-
# Configuration is read from different sources:
|
11
|
-
# - config files (system, global, user, specified on the command line)
|
12
|
-
# - command line options
|
13
|
-
# - any extra config you provide programmatically
|
14
|
-
#
|
15
|
-
# == Config files:
|
16
|
-
# system, global, and user config files are searched in the file system according to
|
17
|
-
# complex rules. First the place where to search them depends on the OS
|
18
|
-
# (Provided by {EasyAppHelper::Core::Config::Places}), and then multiple file extensions are
|
19
|
-
# tested ({EasyAppHelper::Core::Config::CONFIG_FILE_POSSIBLE_EXTENSIONS}). This is basically
|
20
|
-
# performed by the private method {#find_file}. The config specified on command line (if any)
|
21
|
-
# is loaded the same way.
|
22
|
-
#
|
23
|
-
# == Command line:
|
24
|
-
# Any option can be declared as being callable from the command line. Modules add already some
|
25
|
-
# command line options, but the application can obviously add its own (see
|
26
|
-
# {EasyAppHelper::Core::Base#add_command_line_section}).
|
27
|
-
#
|
28
|
-
# Each of the config sources are kept in a separated "layer" and addressed this way using the
|
29
|
-
# #internal_configs attribute reader. But of course the config object provides a "merged" config
|
30
|
-
# result of the computation of all the sources. See the {#to_hash} method to see the order for the
|
31
|
-
# merge.
|
32
|
-
# Any option can be accessed or modified directly using the {#[]} and {#[]=} methods.
|
33
|
-
# Any change to the global config should be done using the {#[]=} method and is kept in the last separated
|
34
|
-
# layer called "modified". Therefore the config can be easily reset using the {#reset}
|
35
|
-
# method.
|
36
|
-
class EasyAppHelper::Core::Config < EasyAppHelper::Core::Base
|
37
|
-
end
|
38
|
-
|
39
|
-
require 'easy_app_helper/core/places'
|
40
|
-
require 'easy_app_helper/core/merge_policies'
|
41
|
-
|
42
|
-
|
43
|
-
class EasyAppHelper::Core::Config < EasyAppHelper::Core::Base
|
44
|
-
include EasyAppHelper::Core::HashesMergePolicies
|
45
|
-
include EasyAppHelper::Core::Config::Places.get_OS_module
|
46
|
-
|
47
|
-
ADMIN_CONFIG_FILENAME = EasyAppHelper.name
|
48
|
-
|
49
|
-
|
50
|
-
# Potential extensions a config file can have
|
51
|
-
CONFIG_FILE_POSSIBLE_EXTENSIONS = %w(conf yml cfg yaml CFG YML YAML Yaml)
|
52
|
-
ADMIN_CONFIG_FILENAME
|
53
|
-
|
54
|
-
# @param [EasyAppHelper::Core::Logger] logger
|
55
|
-
# The logger passed to this constructor should be a temporary logger until the full config is loaded.
|
56
|
-
def initialize(logger)
|
57
|
-
super
|
58
|
-
add_cmd_line_options
|
59
|
-
load_config
|
60
|
-
end
|
61
|
-
|
62
|
-
# After calling the super method, triggers a forced reload of the file based config.
|
63
|
-
# @param [String] name of the config file
|
64
|
-
# @see Base#script_filename=
|
65
|
-
def script_filename=(name)
|
66
|
-
super
|
67
|
-
force_reload
|
68
|
-
end
|
69
|
-
|
70
|
-
# Sets the Application name and passes it to the logger.
|
71
|
-
# @param [String] name
|
72
|
-
# @see Base#app_name=
|
73
|
-
def app_name=(name)
|
74
|
-
super
|
75
|
-
logger.progname = name
|
76
|
-
end
|
77
|
-
|
78
|
-
# Loads all config (command line and config files)
|
79
|
-
# Do not reload a file if already loaded unless forced too.
|
80
|
-
# It *does not flush the "modified" layer*. Use {#reset} instead
|
81
|
-
# @param [Boolean] force to force the reload
|
82
|
-
def load_config(force=false)
|
83
|
-
super()
|
84
|
-
load_layer_config :system, ADMIN_CONFIG_FILENAME, force
|
85
|
-
load_layer_config :global, script_filename, force
|
86
|
-
load_layer_config :user, script_filename, force
|
87
|
-
load_layer_config :specific_file, internal_configs[:command_line][:content][:'config-file'], force
|
88
|
-
end
|
89
|
-
|
90
|
-
# @see #load_config
|
91
|
-
def force_reload
|
92
|
-
load_config true
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
# This is the main method that provides the config as a hash.
|
97
|
-
#
|
98
|
-
# Every layer is kept untouched (and could accessed independently
|
99
|
-
# using {#internal_configs}), while this methods provides a merged config.
|
100
|
-
# @return [Hash] The hash of the merged config.
|
101
|
-
def to_hash
|
102
|
-
merged_config = [:system, :global, :user].inject({}) do |temp_config, config_level|
|
103
|
-
hashes_second_level_merge temp_config, internal_configs[config_level][:content]
|
104
|
-
end
|
105
|
-
if command_line_config[:'config-file']
|
106
|
-
if command_line_config[:'config-override']
|
107
|
-
override_merge merged_config, internal_configs[:specific_file][:content]
|
108
|
-
else
|
109
|
-
hashes_second_level_merge merged_config, internal_configs[:specific_file][:content]
|
110
|
-
end
|
111
|
-
|
112
|
-
end
|
113
|
-
hashes_second_level_merge merged_config, command_line_config
|
114
|
-
hashes_second_level_merge merged_config, internal_configs[:modified][:content]
|
115
|
-
end
|
116
|
-
|
117
|
-
# @param [Object] key: The key to access the data in the merged_config hash (see {#to_hash})
|
118
|
-
# @return [String] Value for this key in the merged config.
|
119
|
-
def [](key)
|
120
|
-
self.to_hash[key]
|
121
|
-
end
|
122
|
-
|
123
|
-
|
124
|
-
# @return [String] The merged config (see {#to_hash}) rendered as Yaml
|
125
|
-
def to_yaml
|
126
|
-
to_hash.to_yaml
|
127
|
-
end
|
128
|
-
|
129
|
-
#############################################################################
|
130
|
-
private
|
131
|
-
|
132
|
-
# Command line options specific to config manipulation
|
133
|
-
def add_cmd_line_options
|
134
|
-
add_command_line_section('Configuration options') do |slop|
|
135
|
-
slop.on 'config-file', 'Specify a config file.', :argument => true
|
136
|
-
slop.on 'config-override', 'If specified override all other config.', :argument => false
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
# Tries to find a config file to be loaded into the config layer cake unless cached.
|
141
|
-
def load_layer_config(layer, filename_or_pattern, force=false)
|
142
|
-
unless_cached(layer, filename_or_pattern, force) do |layer, filename_or_pattern|
|
143
|
-
fetch_config_layer layer, filename_or_pattern
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# Actual loads
|
148
|
-
def fetch_config_layer(layer, filename_or_pattern)
|
149
|
-
if filename_or_pattern.nil?
|
150
|
-
internal_configs[layer] = {content: {}}
|
151
|
-
filename = nil
|
152
|
-
else
|
153
|
-
if File.exists? filename_or_pattern and !File.directory? filename_or_pattern
|
154
|
-
filename = filename_or_pattern
|
155
|
-
else
|
156
|
-
filename = find_file POSSIBLE_PLACES[layer], filename_or_pattern
|
157
|
-
end
|
158
|
-
internal_configs[layer] = {content: load_config_file(filename), source: filename, origin: filename_or_pattern}
|
159
|
-
end
|
160
|
-
ensure
|
161
|
-
logger.info "No config file found for layer #{layer}." if filename.nil?
|
162
|
-
end
|
163
|
-
|
164
|
-
def unless_cached(layer, filename_or_pattern, forced)
|
165
|
-
cached = false
|
166
|
-
if internal_configs[layer]
|
167
|
-
cached = true unless internal_configs[layer][:origin] == filename_or_pattern
|
168
|
-
end
|
169
|
-
if forced or not cached
|
170
|
-
yield layer, filename_or_pattern
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# Tries to find config files according to places (array) given and possible extensions
|
175
|
-
def find_file(places, filename)
|
176
|
-
return nil if places.nil? or filename.nil? or filename.empty?
|
177
|
-
places.each do |dir|
|
178
|
-
CONFIG_FILE_POSSIBLE_EXTENSIONS.each do |ext|
|
179
|
-
filename_with_path = dir + '/' + filename + '.' + ext
|
180
|
-
if File.exists? filename_with_path and !File.directory? filename_with_path
|
181
|
-
return filename_with_path
|
182
|
-
else
|
183
|
-
logger.debug "Trying \"#{filename_with_path}\" as config file."
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
nil
|
188
|
-
end
|
189
|
-
|
190
|
-
def load_config_file(conf_filename)
|
191
|
-
conf = {}
|
192
|
-
return conf if conf_filename.nil?
|
193
|
-
|
194
|
-
begin
|
195
|
-
logger.debug "Loading config file \"#{conf_filename}\""
|
196
|
-
conf = Hash[YAML::load(open(conf_filename)).map { |k, v| [k.to_sym, v] }]
|
197
|
-
rescue => e
|
198
|
-
logger.error "Invalid config file \"#{conf_filename}\". Skipped as not respecting YAML syntax!\n#{e.message}"
|
199
|
-
end
|
200
|
-
conf
|
201
|
-
end
|
202
|
-
|
203
|
-
end
|
1
|
+
################################################################################
|
2
|
+
# EasyAppHelper
|
3
|
+
#
|
4
|
+
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
+
# http://opensource.org/licenses/MIT
|
6
|
+
################################################################################
|
7
|
+
|
8
|
+
require 'yaml'
|
9
|
+
# This is the class that will handle the configuration.
|
10
|
+
# Configuration is read from different sources:
|
11
|
+
# - config files (system, global, user, specified on the command line)
|
12
|
+
# - command line options
|
13
|
+
# - any extra config you provide programmatically
|
14
|
+
#
|
15
|
+
# == Config files:
|
16
|
+
# system, global, and user config files are searched in the file system according to
|
17
|
+
# complex rules. First the place where to search them depends on the OS
|
18
|
+
# (Provided by {EasyAppHelper::Core::Config::Places}), and then multiple file extensions are
|
19
|
+
# tested ({EasyAppHelper::Core::Config::CONFIG_FILE_POSSIBLE_EXTENSIONS}). This is basically
|
20
|
+
# performed by the private method {#find_file}. The config specified on command line (if any)
|
21
|
+
# is loaded the same way.
|
22
|
+
#
|
23
|
+
# == Command line:
|
24
|
+
# Any option can be declared as being callable from the command line. Modules add already some
|
25
|
+
# command line options, but the application can obviously add its own (see
|
26
|
+
# {EasyAppHelper::Core::Base#add_command_line_section}).
|
27
|
+
#
|
28
|
+
# Each of the config sources are kept in a separated "layer" and addressed this way using the
|
29
|
+
# #internal_configs attribute reader. But of course the config object provides a "merged" config
|
30
|
+
# result of the computation of all the sources. See the {#to_hash} method to see the order for the
|
31
|
+
# merge.
|
32
|
+
# Any option can be accessed or modified directly using the {#[]} and {#[]=} methods.
|
33
|
+
# Any change to the global config should be done using the {#[]=} method and is kept in the last separated
|
34
|
+
# layer called "modified". Therefore the config can be easily reset using the {#reset}
|
35
|
+
# method.
|
36
|
+
class EasyAppHelper::Core::Config < EasyAppHelper::Core::Base
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'easy_app_helper/core/places'
|
40
|
+
require 'easy_app_helper/core/merge_policies'
|
41
|
+
|
42
|
+
|
43
|
+
class EasyAppHelper::Core::Config < EasyAppHelper::Core::Base
|
44
|
+
include EasyAppHelper::Core::HashesMergePolicies
|
45
|
+
include EasyAppHelper::Core::Config::Places.get_OS_module
|
46
|
+
|
47
|
+
ADMIN_CONFIG_FILENAME = EasyAppHelper.name
|
48
|
+
|
49
|
+
|
50
|
+
# Potential extensions a config file can have
|
51
|
+
CONFIG_FILE_POSSIBLE_EXTENSIONS = %w(conf yml cfg yaml CFG YML YAML Yaml)
|
52
|
+
ADMIN_CONFIG_FILENAME
|
53
|
+
|
54
|
+
# @param [EasyAppHelper::Core::Logger] logger
|
55
|
+
# The logger passed to this constructor should be a temporary logger until the full config is loaded.
|
56
|
+
def initialize(logger)
|
57
|
+
super
|
58
|
+
add_cmd_line_options
|
59
|
+
load_config
|
60
|
+
end
|
61
|
+
|
62
|
+
# After calling the super method, triggers a forced reload of the file based config.
|
63
|
+
# @param [String] name of the config file
|
64
|
+
# @see Base#script_filename=
|
65
|
+
def script_filename=(name)
|
66
|
+
super
|
67
|
+
force_reload
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sets the Application name and passes it to the logger.
|
71
|
+
# @param [String] name
|
72
|
+
# @see Base#app_name=
|
73
|
+
def app_name=(name)
|
74
|
+
super
|
75
|
+
logger.progname = name
|
76
|
+
end
|
77
|
+
|
78
|
+
# Loads all config (command line and config files)
|
79
|
+
# Do not reload a file if already loaded unless forced too.
|
80
|
+
# It *does not flush the "modified" layer*. Use {#reset} instead
|
81
|
+
# @param [Boolean] force to force the reload
|
82
|
+
def load_config(force=false)
|
83
|
+
super()
|
84
|
+
load_layer_config :system, ADMIN_CONFIG_FILENAME, force
|
85
|
+
load_layer_config :global, script_filename, force
|
86
|
+
load_layer_config :user, script_filename, force
|
87
|
+
load_layer_config :specific_file, internal_configs[:command_line][:content][:'config-file'], force
|
88
|
+
end
|
89
|
+
|
90
|
+
# @see #load_config
|
91
|
+
def force_reload
|
92
|
+
load_config true
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# This is the main method that provides the config as a hash.
|
97
|
+
#
|
98
|
+
# Every layer is kept untouched (and could accessed independently
|
99
|
+
# using {#internal_configs}), while this methods provides a merged config.
|
100
|
+
# @return [Hash] The hash of the merged config.
|
101
|
+
def to_hash
|
102
|
+
merged_config = [:system, :global, :user].inject({}) do |temp_config, config_level|
|
103
|
+
hashes_second_level_merge temp_config, internal_configs[config_level][:content]
|
104
|
+
end
|
105
|
+
if command_line_config[:'config-file']
|
106
|
+
if command_line_config[:'config-override']
|
107
|
+
override_merge merged_config, internal_configs[:specific_file][:content]
|
108
|
+
else
|
109
|
+
hashes_second_level_merge merged_config, internal_configs[:specific_file][:content]
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
hashes_second_level_merge merged_config, command_line_config
|
114
|
+
hashes_second_level_merge merged_config, internal_configs[:modified][:content]
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param [Object] key: The key to access the data in the merged_config hash (see {#to_hash})
|
118
|
+
# @return [String] Value for this key in the merged config.
|
119
|
+
def [](key)
|
120
|
+
self.to_hash[key]
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# @return [String] The merged config (see {#to_hash}) rendered as Yaml
|
125
|
+
def to_yaml
|
126
|
+
to_hash.to_yaml
|
127
|
+
end
|
128
|
+
|
129
|
+
#############################################################################
|
130
|
+
private
|
131
|
+
|
132
|
+
# Command line options specific to config manipulation
|
133
|
+
def add_cmd_line_options
|
134
|
+
add_command_line_section('Configuration options') do |slop|
|
135
|
+
slop.on 'config-file', 'Specify a config file.', :argument => true
|
136
|
+
slop.on 'config-override', 'If specified override all other config.', :argument => false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Tries to find a config file to be loaded into the config layer cake unless cached.
|
141
|
+
def load_layer_config(layer, filename_or_pattern, force=false)
|
142
|
+
unless_cached(layer, filename_or_pattern, force) do |layer, filename_or_pattern|
|
143
|
+
fetch_config_layer layer, filename_or_pattern
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Actual loads
|
148
|
+
def fetch_config_layer(layer, filename_or_pattern)
|
149
|
+
if filename_or_pattern.nil?
|
150
|
+
internal_configs[layer] = {content: {}}
|
151
|
+
filename = nil
|
152
|
+
else
|
153
|
+
if File.exists? filename_or_pattern and !File.directory? filename_or_pattern
|
154
|
+
filename = filename_or_pattern
|
155
|
+
else
|
156
|
+
filename = find_file POSSIBLE_PLACES[layer], filename_or_pattern
|
157
|
+
end
|
158
|
+
internal_configs[layer] = {content: load_config_file(filename), source: filename, origin: filename_or_pattern}
|
159
|
+
end
|
160
|
+
ensure
|
161
|
+
logger.info "No config file found for layer #{layer}." if filename.nil?
|
162
|
+
end
|
163
|
+
|
164
|
+
def unless_cached(layer, filename_or_pattern, forced)
|
165
|
+
cached = false
|
166
|
+
if internal_configs[layer]
|
167
|
+
cached = true unless internal_configs[layer][:origin] == filename_or_pattern
|
168
|
+
end
|
169
|
+
if forced or not cached
|
170
|
+
yield layer, filename_or_pattern
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Tries to find config files according to places (array) given and possible extensions
|
175
|
+
def find_file(places, filename)
|
176
|
+
return nil if places.nil? or filename.nil? or filename.empty?
|
177
|
+
places.each do |dir|
|
178
|
+
CONFIG_FILE_POSSIBLE_EXTENSIONS.each do |ext|
|
179
|
+
filename_with_path = dir + '/' + filename + '.' + ext
|
180
|
+
if File.exists? filename_with_path and !File.directory? filename_with_path
|
181
|
+
return filename_with_path
|
182
|
+
else
|
183
|
+
logger.debug "Trying \"#{filename_with_path}\" as config file."
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def load_config_file(conf_filename)
|
191
|
+
conf = {}
|
192
|
+
return conf if conf_filename.nil?
|
193
|
+
|
194
|
+
begin
|
195
|
+
logger.debug "Loading config file \"#{conf_filename}\""
|
196
|
+
conf = Hash[YAML::load(open(conf_filename)).map { |k, v| [k.to_sym, v] }]
|
197
|
+
rescue => e
|
198
|
+
logger.error "Invalid config file \"#{conf_filename}\". Skipped as not respecting YAML syntax!\n#{e.message}"
|
199
|
+
end
|
200
|
+
conf
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
@@ -1,103 +1,111 @@
|
|
1
|
-
################################################################################
|
2
|
-
# EasyAppHelper
|
3
|
-
#
|
4
|
-
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
-
# http://opensource.org/licenses/MIT
|
6
|
-
################################################################################
|
7
|
-
|
8
|
-
require 'logger'
|
9
|
-
require 'singleton'
|
10
|
-
|
11
|
-
# Official Ruby Logger re-opened to introduce a method to hand-over the temporary history from a temporary logger
|
12
|
-
# to the definitive one.
|
13
|
-
# TODO: Ensure only the messages that are above the current level are displayed when handing over to the definitive logger.
|
14
|
-
class Logger
|
15
|
-
def handing_over_to(log)
|
16
|
-
history = []
|
17
|
-
history = @logdev.dev.history if @logdev.dev.respond_to? :history
|
18
|
-
@logdev.close
|
19
|
-
@logdev = LogDevice.new log
|
20
|
-
history.each do |msg|
|
21
|
-
@logdev.write msg if ENV['DEBUG_EASY_MODULES'] or (msg =~ /^[WE]/)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# This is the logger that will be used by the application and any class that include {EasyAppHelper} module. It is
|
27
|
-
# configured by the {EasyAppHelper::Core::Config Config} object, and provides a temporary logger until the config
|
28
|
-
# is fully loaded.
|
29
|
-
class EasyAppHelper::Core::Logger < Logger
|
30
|
-
include Singleton
|
31
|
-
|
32
|
-
|
33
|
-
def initialize
|
34
|
-
@config = {}
|
35
|
-
super(TempLogger.new)
|
36
|
-
self.level = Severity::DEBUG
|
37
|
-
debug "Temporary initialisation logger created..."
|
38
|
-
end
|
39
|
-
|
40
|
-
# Change the log level while keeping the config in sync.
|
41
|
-
def level=(level)
|
42
|
-
super
|
43
|
-
@config[:'log-level'] = level
|
44
|
-
end
|
45
|
-
|
46
|
-
# Displays the message according to application verbosity and logs it as info.
|
47
|
-
def puts_and_logs(msg)
|
48
|
-
puts msg if @config[:verbose]
|
49
|
-
info(msg)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Reset the logger regarding the config provided
|
53
|
-
def set_app_config(config)
|
54
|
-
@config = config
|
55
|
-
add_cmd_line_options
|
56
|
-
@config.load_config
|
57
|
-
debug "Config layers:\n#{@config.internal_configs.to_yaml}"
|
58
|
-
debug "Merged config:\n#{@config.to_yaml}"
|
59
|
-
if config[:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
def
|
93
|
-
@history
|
94
|
-
end
|
95
|
-
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
1
|
+
################################################################################
|
2
|
+
# EasyAppHelper
|
3
|
+
#
|
4
|
+
# Copyright (c) 2013 L.Briais under MIT license
|
5
|
+
# http://opensource.org/licenses/MIT
|
6
|
+
################################################################################
|
7
|
+
|
8
|
+
require 'logger'
|
9
|
+
require 'singleton'
|
10
|
+
|
11
|
+
# Official Ruby Logger re-opened to introduce a method to hand-over the temporary history from a temporary logger
|
12
|
+
# to the definitive one.
|
13
|
+
# TODO: Ensure only the messages that are above the current level are displayed when handing over to the definitive logger.
|
14
|
+
class Logger
|
15
|
+
def handing_over_to(log)
|
16
|
+
history = []
|
17
|
+
history = @logdev.dev.history if @logdev.dev.respond_to? :history
|
18
|
+
@logdev.close
|
19
|
+
@logdev = LogDevice.new log
|
20
|
+
history.each do |msg|
|
21
|
+
@logdev.write msg if ENV['DEBUG_EASY_MODULES'] or (msg =~ /^[WE]/)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# This is the logger that will be used by the application and any class that include {EasyAppHelper} module. It is
|
27
|
+
# configured by the {EasyAppHelper::Core::Config Config} object, and provides a temporary logger until the config
|
28
|
+
# is fully loaded.
|
29
|
+
class EasyAppHelper::Core::Logger < Logger
|
30
|
+
include Singleton
|
31
|
+
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@config = {}
|
35
|
+
super(TempLogger.new)
|
36
|
+
self.level = Severity::DEBUG
|
37
|
+
debug "Temporary initialisation logger created..."
|
38
|
+
end
|
39
|
+
|
40
|
+
# Change the log level while keeping the config in sync.
|
41
|
+
def level=(level)
|
42
|
+
super
|
43
|
+
@config[:'log-level'] = level
|
44
|
+
end
|
45
|
+
|
46
|
+
# Displays the message according to application verbosity and logs it as info.
|
47
|
+
def puts_and_logs(msg)
|
48
|
+
puts msg if @config[:verbose]
|
49
|
+
info(msg)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Reset the logger regarding the config provided
|
53
|
+
def set_app_config(config)
|
54
|
+
@config = config
|
55
|
+
add_cmd_line_options
|
56
|
+
@config.load_config
|
57
|
+
debug "Config layers:\n#{@config.internal_configs.to_yaml}"
|
58
|
+
debug "Merged config:\n#{@config.to_yaml}"
|
59
|
+
if config[:debug]
|
60
|
+
if config[:'log-file']
|
61
|
+
handing_over_to config[:'log-file']
|
62
|
+
elsif config[:"debug-on-err"]
|
63
|
+
handing_over_to STDERR
|
64
|
+
else
|
65
|
+
handing_over_to STDOUT
|
66
|
+
end
|
67
|
+
else
|
68
|
+
close
|
69
|
+
end
|
70
|
+
self.level = config[:'log-level'] ? config[:'log-level'] : Severity::WARN
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
|
77
|
+
def add_cmd_line_options
|
78
|
+
@config.add_command_line_section('Debug and logging options') do |slop|
|
79
|
+
slop.on :debug, 'Run in debug mode.', :argument => false
|
80
|
+
slop.on 'debug-on-err', 'Run in debug mode with output to stderr.', :argument => false
|
81
|
+
slop.on 'log-level', "Log level from 0 to 5, default #{Severity::WARN}.", :argument => true, :as => Integer
|
82
|
+
slop.on 'log-file', 'File to log to.', :argument => true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# This class will act as a temporary logger, actually just keeping the history until the real
|
87
|
+
# configuration for the logger is known. Then the history is displayed or not regarding the
|
88
|
+
# definitive logger configuration.
|
89
|
+
class TempLogger
|
90
|
+
attr_reader :history
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
@history = []
|
94
|
+
end
|
95
|
+
|
96
|
+
def write(data)
|
97
|
+
return if closed?
|
98
|
+
@history << data if @history
|
99
|
+
end
|
100
|
+
|
101
|
+
def close
|
102
|
+
@closed = true
|
103
|
+
end
|
104
|
+
|
105
|
+
def opened?() not @closed ; end
|
106
|
+
def closed?() @closed ; end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
|