snarl-snp 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,11 @@
1
1
  require 'socket'
2
-
2
+ require 'yaml'
3
3
  $LOAD_PATH.unshift(File.dirname(File.expand_path(__FILE__)))
4
4
 
5
5
  require 'snp/action'
6
- require 'snp/snp'
6
+ require 'snp/snp_procedure'
7
+ require 'snp/config'
7
8
  require 'snp/request'
8
9
  require 'snp/response'
9
10
  require 'snp/error'
10
- require 'snp/config'
11
- # require 'snp/addon'
11
+ require 'snp/snp'
@@ -13,9 +13,10 @@ class Snarl
13
13
  #
14
14
  # Snarl sends back a casual error when +app+ is already registered.
15
15
  # It is treated as SNP::SNPError::Casual::SNP_ERROR_ALREADY_REGISTERED.
16
- def register(app=nil)
17
- @app = app
18
- cmds = {:action => 'register', :app => app}
16
+ def register(app = nil)
17
+ # when self['app'] == nil/unset and register(nil), SNARL receives SNP_ERROR_BAD_PACKET
18
+ self['app'] = app if app
19
+ cmds = {:action => 'register', :app => self['app']}
19
20
  request(Request.new(cmds))
20
21
  end
21
22
  alias :app= :register
@@ -33,8 +34,8 @@ class Snarl
33
34
  def add_class(classid, classtitle=nil)
34
35
  # TODO: add_class(app=nil, classid, classtitle=nil)
35
36
  # type=SNP#?version=1.0#?action=add_class#?class=t returns (107) Bad Packet
36
- raise "#{self}#register(appname) required before add_class" unless @app
37
- cmds = {:action => 'add_class', :app => @app, :class => classid.to_s, :title => classtitle}
37
+ raise "registering is required. #{self}#register(appname) before #add_class" unless self['app']
38
+ cmds = {:action => 'add_class', :app => self['app'], :class => classid.to_s, :title => classtitle}
38
39
  request(Request.new(cmds))
39
40
  end
40
41
 
@@ -66,7 +67,7 @@ class Snarl
66
67
  # Snarl sends back a casual error when +app+ is not registered.
67
68
  # It is treated as SNP::SNPError::Casual::SNP_ERROR_NOT_REGISTERED.
68
69
  def unregister(app=nil)
69
- app = app || @app
70
+ app = app || self['app']
70
71
  raise "#{self}#unregister requires appname." unless app
71
72
  cmds = {:action => 'unregister', :app => app}
72
73
  request(Request.new(cmds))
@@ -126,11 +127,14 @@ class Snarl
126
127
  res[command] = keyhash_value if keyhash_value
127
128
  end
128
129
  res[:action] = 'notification'
129
- res[:app] = @app if (res[:app].nil? && @app) # default notification
130
- res[:app] = nil if res[:app] == :anonymous # from snp.show_message
131
- res[:title] = (@title || DEFAULT_TITLE) unless res[:title]
132
- res[:timeout] = (@timeout || DEFAULT_TIMEOUT) unless res[:timeout]
133
- res[:icon] = icon(res[:icon]) if res[:icon]
130
+ res[:app] = self['app'] if (res[:app].nil? && self['app']) # default notification
131
+ res[:title] = (res[:title] || self['title'] || DEFAULT_TITLE)
132
+ res[:timeout] = (res[:timeout] || self['timeout'] || DEFAULT_TIMEOUT)
133
+ if res[:icon] then
134
+ res[:icon] = icon(res[:icon])
135
+ elsif self['icon'] then
136
+ res[:icon] = self['icon']
137
+ end
134
138
  return res
135
139
  end
136
140
  end
@@ -0,0 +1,69 @@
1
+ require 'snp'
2
+ class Snarl
3
+ class SNP
4
+ module AutoSNP
5
+ @host=nil
6
+ @port=nil
7
+ @icondir=nil
8
+ @icon_ok=nil
9
+ @icon_fail=nil
10
+ @icon_pending=nil
11
+ @timeout_ok=nil
12
+ @timeout_fail=nil
13
+
14
+ attr_accessor :host, :port
15
+ attr_writer :icondir, :icon_ok, :icon_fail, :icon_pending, :timeout_ok, :timeout_fail
16
+
17
+ def snp
18
+ Snarl::SNP.load(<<YAML)
19
+ host : #{host}
20
+ port : #{port}
21
+ app : Autotest::Snarl
22
+ "class" :
23
+ - ['green', 'test ok']
24
+ - ['red', 'test fail']
25
+ - ['yellow', 'test pending']
26
+ - ['info', 'system message']
27
+ iconset :
28
+ green : #{File.join(icondir, icon_ok)}
29
+ red : #{File.join(icondir, icon_fail)}
30
+ yellow : #{File.join(icondir, icon_pending)}
31
+ YAML
32
+ end
33
+
34
+ # Windows Snarl shortcut's "working folder" (left click property)
35
+ # %HOME%\Application Data\full phat\snarl\styles
36
+ def icondir ; @icondir ||= './' ; end
37
+
38
+ # %HOME%\Application Data\full phat\snarl\styles\ok.png works fine
39
+ def icon_ok ; @icon_ok ||= "ok.png" ; end
40
+ def icon_fail ; @icon_fail ||= "fail.png" ; end
41
+ def icon_pending ; @icon_pending ||= "pending.png" ; end
42
+
43
+ def timeout_ok ; @timeout_ok ||= 5 ; end
44
+ def timeout_fail ; @timeout_fail ||= 10 ; end
45
+
46
+ def timeout(state)
47
+ case state
48
+ when :green then timeout_ok.to_i
49
+ when :red then timeout_fail.to_i
50
+ else 5
51
+ end
52
+ end
53
+
54
+ def classname(state)
55
+ state.to_s
56
+ end
57
+
58
+ def snarl(title, text, state)
59
+ snp.notification(
60
+ :title => title,
61
+ :text => text,
62
+ :icon => state.to_s,
63
+ :timeout => timeout(state),
64
+ :class => classname(state)
65
+ )
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,31 +1,123 @@
1
-
2
- # when config file exists, require this config
3
1
  class Snarl
4
2
  class SNP
5
3
  class Config
6
4
 
7
5
  DEFAULT_HOST = '127.0.0.1'
8
6
  DEFAULT_PORT = 9887
9
- @host = nil
10
- @port = nil
11
7
 
12
- def self.host
13
- @host || ENV['SNARL_HOST'] || DEFAULT_HOST
14
- end
15
- def self.host=(v)
16
- @host = if v then v.to_s else nil end
8
+ def initialize
9
+ @config = {}
10
+ default_config
17
11
  end
18
12
 
19
- def self.port
20
- @port || ENV['SNARL_PORT'] || DEFAULT_PORT
21
- end
22
- def self.port=(v)
23
- @port = if v then v.to_i else nil end
13
+ attr_reader :config # mainly for debug
14
+
15
+ def default_config
16
+ self['host'] = if $SAFE > 0 then DEFAULT_HOST else ENV['SNARL_HOST'] || DEFAULT_HOST end
17
+ self['port'] = if $SAFE > 0 then DEFAULT_PORT else ENV['SNARL_PORT'] || DEFAULT_PORT end
24
18
  end
19
+ private :default_config
20
+
21
+ def []=(k, v) ; Normalize.store(k, v, @config) ; end
22
+ def [](k) ; @config[k.to_s] ; end
23
+ def reset ; @config = {} ; end
24
+ def to_yaml ; @config.to_yaml ; end
25
+
26
+ class Normalize
27
+
28
+ def self.store(k, v, hash)
29
+ nkey, nvalue = new(k, v).normalize
30
+ hash.store(nkey, nvalue) if nkey && nvalue != nil
31
+ end
32
+
33
+ def initialize(k, v)
34
+ @key, @value = k, v
35
+ end
36
+
37
+ def normalize
38
+ # NOTE: [xxx, nil] is not set to @config
39
+ # TODO : [k, v] should be equal to {k ,v}
40
+ v = @value
41
+ case @key.to_s
42
+ when 'host' then
43
+ ['host', if is_yaml_undef?(v) then nil else v end]
44
+ when 'port' then
45
+ # {:port => '9887'} is {'port' => 9887}
46
+ ['port', if is_yaml_undef?(v) then nil else v.to_i end]
47
+ when 'app', 'application', 'name', 'register' then
48
+ ['app', if is_yaml_undef?(v) then nil else v end]
49
+ when 'class', 'add_class', 'classes' then
50
+ # {:class => 'cls'} and {'add_class' => {'cls' => nil}} are {'class' => ['cls', nil]}
51
+ ['class', extract_classes(v)]
52
+ when 'title' then
53
+ ['title', if is_yaml_undef?(v) then nil else v end]
54
+ when 'text', 'body', 'msg' then
55
+ ['text', if is_yaml_undef?(v) then nil else v end]
56
+ when 'timeout', 'duration', 'sec' then
57
+ ['timeout', if is_yaml_undef?(v) then 0 else v.to_i end] # "timeout: nil" is sticky
58
+ when 'sticky' then
59
+ ['timeout', if is_yaml_false?(v) then nil else 0 end]
60
+ when 'icon' then # NOTE: is "this notification icon", not "iconset setting"
61
+ ['icon', if is_yaml_undef?(v) then nil else v end]
62
+ when 'notification', 'notify', 'message' then
63
+ ['notification', if is_yaml_undef?(v) then nil else v end]
64
+ when 'unregister' then
65
+ ['unregister', if is_yaml_false?(v) then false else true end]
66
+ when 'iconset' then
67
+ ['iconset', if is_yaml_undef?(v) then nil else v end]
68
+
69
+ when 'log', 'logger' then # useless on yaml?
70
+ ['logger', v]
71
+ when 'logfile' then
72
+ ['logfile', extract_logfile(v)]
73
+ when 'loglevel', 'logger.level', 'log_level' then
74
+ ['loglevel', extract_loglevel(v)]
75
+
76
+ when 'config' then
77
+ ['config', if is_yaml_undef?(v) then nil else v end]
78
+ when 'yaml' then
79
+ ['yaml', if is_yaml_undef?(v) then nil else v end]
80
+
81
+ else [@key.to_s, v] # or raise?
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def is_yaml_undef?(v)
88
+ v == 'nil' || v == nil || v == ':nil' || v == :nil || v == '' || v == [] || v == {}
89
+ end
90
+ def is_yaml_false?(v)
91
+ is_yaml_undef?(v) || v == false || v == 'false' || v == :false || v == ':false'
92
+ end
93
+
94
+ def extract_classes(v)
95
+ if v.kind_of?(Array) then
96
+ res = []
97
+ v.each do |a|
98
+ pair = [a].flatten
99
+ pair.push(nil) if pair.size == 1
100
+ res << pair
101
+ end
102
+ return res
103
+ elsif v.kind_of?(String)
104
+ return [[v, nil]]
105
+ else
106
+ return nil
107
+ end
108
+ end
109
+
110
+ def extract_logfile(v)
111
+ if is_yaml_undef?(v) then nil else {'$stdout' => $stdout, '$stderr' => $stderr}[v.to_s] || v end
112
+ end
25
113
 
26
- def self.reset
27
- self.host = nil
28
- self.port = nil
114
+ def extract_loglevel(v)
115
+ if is_yaml_undef?(v) then
116
+ return 0
117
+ else
118
+ return /\d/ =~ v.to_s ? v.to_s.to_i : (%w(DEBUG INFO WARN ERROR FATAL).index(v.to_s.upcase) || 0)
119
+ end
120
+ end
29
121
  end
30
122
  end
31
123
  end
@@ -16,6 +16,9 @@ class Snarl
16
16
  class SNP_OK < Casual ; end
17
17
  # (0) OK
18
18
 
19
+ class SNP_ERROR_NOT_RUNNING < Casual ; end
20
+ # (201) Incoming network notification handling has been disabled by the user.
21
+
19
22
  class SNP_ERROR_NOT_REGISTERED < Casual ; end
20
23
  # (202) The application hasn't been registered.
21
24
 
@@ -25,11 +28,12 @@ class Snarl
25
28
  class SNP_ERROR_CLASS_ALREADY_EXISTS < Casual ; end
26
29
  # (204) Class is already registered.
27
30
 
28
- class Fatal < SNPError ; end
29
-
30
- class SNP_ERROR_FAILED < Fatal ; end
31
+ # "Do not Disturb" often raises this error...
32
+ class SNP_ERROR_FAILED < Casual ; end #Fatal ; end
31
33
  # (101) An internal error occurred - usually this represents a fault within Snarl itself.
32
34
 
35
+ class Fatal < SNPError ; end
36
+
33
37
  class SNP_ERROR_UNKNOWN_COMMAND < Fatal ; end
34
38
  # (102) An unknown action was specified.
35
39
 
@@ -39,9 +43,6 @@ class Snarl
39
43
  class SNP_ERROR_BAD_PACKET < Fatal ; end
40
44
  # (107) The command packet is wrongly formed.
41
45
 
42
- class SNP_ERROR_NOT_RUNNING < Fatal ; end
43
- # (201) Incoming network notification handling has been disabled by the user.
44
-
45
46
  class RUBYSNARL_UNKNOWN_RESPONSE < Fatal ; end
46
47
  # (???) Snarl returns unknown return code.
47
48
 
@@ -23,60 +23,70 @@ class Snarl
23
23
  # make SNP request string from command hash and is Request object.
24
24
  def initialize(cmd_hash={})
25
25
  @commands = {}.update(cmd_hash)
26
+ normalize unless @commands.empty?
26
27
  end
27
28
 
28
29
  attr_reader :commands
29
30
 
30
31
  # Adds command key and value to Request
31
- def []=(cmdkey, value) ; @commands[cmdkey] = value ; end # TODO: normalize
32
+ def []=(cmdkey, value)
33
+ norm_cmdkey = normalize_cmdkey(cmdkey)
34
+ if norm_cmdkey == 'action' then
35
+ @commands['action'] = normalize_action_value(value)
36
+ else
37
+ @commands[norm_cmdkey] = normalize_value(value)
38
+ end
39
+ end
32
40
  # Returns command value for command key
33
- def [](cmdkey) ; @commands[cmdkey] ; end
41
+ def [](cmdkey) ; @commands[cmdkey] ; end
34
42
 
35
43
  # Returns Request query string with SNP_TERMINAL_STRING "\r\n"
36
44
  def to_str ; query + SNP_TERMINAL_STRING ; end # FIXME: include "\r\n"?
37
45
  alias :to_s :to_str
38
46
  # Returns Request query string. has no SNP_TERMINAL_STRING "\r\n".
39
- def inspect ; query ; end
47
+ def inspect ; query.inspect ; end
40
48
  def action ; @commands['action'] ; end
41
49
 
42
50
  private
43
51
 
44
- def order_command_pair
45
- action = @commands['action']
52
+ def align_command_pair
46
53
  @commands.to_a.sort_by{|pair| SNP_ACTIONS[action].index(pair[0])}
47
54
  end
48
55
 
49
56
  def query
50
- normalize
51
- order_command_pair.map{|pair| pair.join('=')}.join(SNP_SEPARATOR)
57
+ # @commands is already normalized
58
+ align_command_pair.map{|pair| pair.join('=')}.join(SNP_SEPARATOR)
52
59
  end
53
60
 
54
- # normalize item pairs
61
+ # normalize command item pairs {cmdkey => value}
55
62
  # - symbol keys and upcase KEYS are normalized into downcased string keys.
56
- # - query should not have any "\r". use "\n"
57
- # - when value is nil, delete the item pair.
63
+ # - value should not have any "\r". use one "\n" as a newline.
64
+ # - {'action' => 'add-class' or :add_class} are {'action' => 'add_class'}.
65
+ # - when value is nil, delete the pair.
58
66
  def normalize
59
- norm_commands = Hash[*@commands.map{|k, v| [crlf2lf(k).downcase, crlf2lf(v)]}.flatten]
60
- action = normalize_action(norm_commands['action'])
61
- norm_commands['action'] = action
67
+ unnormalized_commands = @commands.dup
62
68
  @commands = SNP_HEADER.dup
63
- available_commands_in(action).each do |cmd|
64
- @commands[cmd] = norm_commands[cmd] if norm_commands[cmd]
65
- end
69
+ unnormalized_commands.each{|cmdkey, value| self[cmdkey] = value}
70
+ available_commands = SNP_ACTIONS[self.action] || [] # or raise
71
+ @commands.delete_if{|cmdkey, value| !available_commands.include?(cmdkey)}
72
+ @commands.delete_if{|cmdkey, value| value.nil?} # || value.empty? # TODO: "timeout=" is vaild SNP?
73
+ @commands
66
74
  end
67
75
 
68
- def normalize_action(action_type)
69
- action_type.downcase.gsub(/-/){'_'}.sub(/\Aaddclass\Z/){'add_class'}
76
+ def normalize_cmdkey(cmdkey)
77
+ crlf2lf(cmdkey).downcase
70
78
  end
71
-
72
- def available_commands_in(action)
73
- SNP_ACTIONS[action] || {}
79
+ def normalize_value(value)
80
+ crlf2lf(value)
74
81
  end
75
82
 
76
83
  def crlf2lf(s)
77
84
  s ? s.to_s.gsub(/\r\n/){"\n"}.gsub(/\r/){"\n"} : s
78
85
  end
79
86
 
87
+ def normalize_action_value(value)
88
+ normalize_value(value).downcase.gsub(/-/){'_'}.sub(/\Aaddclass\Z/){'add_class'}
89
+ end
80
90
  end
81
91
  end
82
92
  end
@@ -31,6 +31,7 @@ class Snarl
31
31
  def inspect ; @response.chomp ; end # p response #=> "SNP/1.1/0/OK/456"
32
32
 
33
33
  def ok? ; code.to_i.zero? ; end
34
+ def request_str ; request ? request.to_s : nil ; end
34
35
  end
35
36
  end
36
37
  end
@@ -3,6 +3,7 @@ class Snarl # conpat for ruby-snarl
3
3
  class SNP
4
4
 
5
5
  include Action
6
+ include SNPProcedure
6
7
 
7
8
  # default "timeout command" value. popup disappers in 10 seconds.
8
9
  DEFAULT_TIMEOUT = 10
@@ -11,49 +12,60 @@ class Snarl # conpat for ruby-snarl
11
12
  DEFAULT_TITLE = 'Ruby-Snarl'
12
13
 
13
14
  # Snarl::SNP.new('127.0.0.1', 9887)
14
- def initialize(host=nil, port=nil, verbose=false)
15
- @host = host
16
- @port = port
17
- @verbose = verbose
18
- @logger = nil
19
- @app = nil
20
- @timeout = nil
21
- @iconset = {}
22
- @title = nil
15
+ def initialize(host=nil, port=nil, verbose=false, &block)
16
+ @config = Config.new
17
+ if host && YAML.load(host).kind_of?(Hash) then
18
+ port.respond_to?(:debug) ? load(host, port, &block) : load(host, nil, &block)
19
+ else
20
+ self['host'] = host
21
+ self['port'] = port
22
+ self['verbose'] = verbose
23
+ yield(self) if block_given?
24
+ end
23
25
  end
26
+ attr_reader :config
27
+
28
+ def []=(k, v) ; @config[k] =v ; end
29
+ def [](k) ; @config[k] ; end
24
30
 
25
31
  # When you set it true, all unimportant SNP errors raise.
26
32
  # Default is false, Snarl::SNP::Error::Casual are disabled.
27
- attr_accessor :verbose
28
-
29
- # a value of SNP command "app".
30
- attr_reader :app
33
+ def verbose=(v) ; self['verbose'] = v ; end
34
+ def verbose ; self['verbose'] ; end
31
35
 
32
- attr_accessor :title
36
+ # # a value of SNP command "app".
37
+ # attr_reader :app
38
+ #
39
+ # attr_accessor :title
33
40
 
34
- # a value of SNP command "timeout".
35
- attr_accessor :timeout
41
+ # # a value of SNP command "timeout".
42
+ # attr_accessor :timeout
36
43
 
37
44
  # set Logger object. It is used when sending request and getting response.
38
45
  def logger=(logger)
39
- @logger = (logger.kind_of?(Class) ? logger.new($stdout) : logger)
46
+ self['logger'] = (logger.kind_of?(Class) ? logger.new($stdout) : logger)
40
47
  end
48
+ def logger ; self['logger'] ; end
41
49
 
42
50
  # send Snarl::SNP::Request/Hash/String and get Snarl::SNP::Response fron Snarl.
43
51
  # When the response "fatal" response, raise errors.
44
52
  # When method +verbose+ returns true, "casual" errors also raises.
45
53
  def request(req)
46
54
  req = Request.new(req) if req.kind_of?(Hash)
47
- debug(req)
55
+ action = if req.kind_of?(Request) then req.action else '(string)' end
56
+ debug("#{action}: #{req.inspect}")
48
57
  begin
49
- action = req.kind_of?(Request) ? req.action : '(string)'
50
58
  res = get_response(req)
51
59
  info("#{action}: #{res.inspect}")
52
60
  rescue Error::Casual => ex
53
61
  info("#{action}: (ignored) #{ex.message}")
54
62
  raise if verbose
63
+ res = ex.response
55
64
  rescue Error::Fatal => ex
56
- info("#{action}: #{ex.message}")
65
+ error("#{action}: #{ex.message}")
66
+ raise
67
+ rescue Errno::ECONNREFUSED => ex
68
+ error("#{ex.message} / #{self['host'].inspect}:#{self['port'].inspect}")
57
69
  raise
58
70
  end
59
71
  return res
@@ -63,25 +75,22 @@ class Snarl # conpat for ruby-snarl
63
75
 
64
76
  # add_classes('type1', 'type2', 'type3')
65
77
  # add_classes(['type1', desc1], ['type2', desc2], ['type3', desc3])
78
+ # add_classes(*array_of_pairs)
79
+ # returns [add_class_response1, add_class_response2, add_class_response3]
66
80
  def add_classes(*classes)
67
- classes.each do |classpair|
68
- classpair = [classpair, nil] if classpair.kind_of?(String)
69
- add_class(*classpair)
70
- end
81
+ classes.map{|e| e.kind_of?(String) ? [e, nil] : e}.map{|p| add_class(*p)}
71
82
  end
72
83
 
73
84
  # returns icon path if SNP knows. optional.
74
85
  def icon(s)
75
- if @iconset.has_key?(s) then @iconset[s] else s end
86
+ if self['iconset'] && self['iconset'].has_key?(s) then self['iconset'][s] else s end
76
87
  end
77
88
 
78
89
  # set icons pair. quite optional.
79
- # snp.iconset(:red => 'red.jpg')
90
+ # snp.iconset({:red => 'red.jpg'})
80
91
  # snp.notification('title', 'text', :red) #=> sends "icon=red.jpg"
81
92
  # snp.notification('title', 'text', 'blue') #=> sends "icon=blue"
82
- def iconset(icons)
83
- @iconset = icons
84
- end
93
+ def iconset(icons) ; self['iconset'] = icons ; end
85
94
  alias :icons :iconset
86
95
 
87
96
  def ping
@@ -106,9 +115,11 @@ class Snarl # conpat for ruby-snarl
106
115
  client
107
116
  end
108
117
 
109
- # send message only. app is "anonymous".
110
- # Snarl::SNP.show_message(host, 9887, title, text, tomeout, icon)
111
- # Snarl::SNP.show_message(host, title, text, tomeout, icon)
118
+ # send message only. app and class is "anonymous".
119
+ # Snarl::SNP.show_message(host, 9887, title, text, timeout, icon)
120
+ # Snarl::SNP.show_message(host, title, text, timeout, icon)
121
+ # Snarl::SNP.show_message(host, title, text)
122
+ # Snarl::SNP.show_message(host, text)
112
123
  def self.show_message(host, port, title=nil, text=nil, timeout=nil, icon=nil)
113
124
  # TODO: (host, title, text, 10)
114
125
  if port.kind_of?(String) && icon.nil? then
@@ -124,19 +135,23 @@ class Snarl # conpat for ruby-snarl
124
135
 
125
136
  private
126
137
 
127
- def get_response(req)
128
- host = @host || Config.host
129
- port = @port || Config.port
130
- TCPSocket.open(host, port) do |s|
138
+ def send(req)
139
+ # normalize just before using # FIXME:
140
+ TCPSocket.open(self['host'], self['port']) do |s|
131
141
  s.write(req)
132
- res = Response.new(s.gets)
133
- res.request = req
134
- res
142
+ s.gets
135
143
  end
136
144
  end
137
145
 
138
- def info(m); @logger.info(m) if @logger; end
139
- def debug(m); @logger.debug(m) if @logger; end
146
+ def get_response(req)
147
+ res = Response.new(send(req))
148
+ res.request = req
149
+ res
150
+ end
151
+
152
+ def error(m); logger.error(m) if logger ; end
153
+ def info(m); logger.info(m) if logger ; end
154
+ def debug(m); logger.debug(m) if logger ; end
140
155
 
141
156
  end
142
157
  end