asir 0.2.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/.gitignore +11 -0
- data/Gemfile +16 -0
- data/README.textile +50 -0
- data/Rakefile +83 -0
- data/VERSION +1 -0
- data/asir.gemspec +36 -0
- data/asir.riterate.yml +114 -0
- data/bin/asir +6 -0
- data/doc/Rakefile +8 -0
- data/doc/asir-sequence.pic +84 -0
- data/doc/asir-sequence.svg +1559 -0
- data/doc/sequence.pic +430 -0
- data/example/asir_control.sh +24 -0
- data/example/asir_control_client_http.rb +14 -0
- data/example/asir_control_client_zmq.rb +15 -0
- data/example/config/asir_config.rb +63 -0
- data/example/delayed_service.rb +15 -0
- data/example/ex01.rb +12 -0
- data/example/ex02.rb +12 -0
- data/example/ex03.rb +19 -0
- data/example/ex04.rb +33 -0
- data/example/ex05.rb +16 -0
- data/example/ex06.rb +26 -0
- data/example/ex07.rb +28 -0
- data/example/ex08.rb +30 -0
- data/example/ex09.rb +25 -0
- data/example/ex10.rb +24 -0
- data/example/ex11.rb +48 -0
- data/example/ex12.rb +34 -0
- data/example/ex13.rb +35 -0
- data/example/ex14.rb +30 -0
- data/example/ex15.rb +13 -0
- data/example/ex16.rb +33 -0
- data/example/ex17.rb +41 -0
- data/example/ex18.rb +62 -0
- data/example/ex19.rb +32 -0
- data/example/ex20.rb +28 -0
- data/example/ex21.rb +28 -0
- data/example/ex22.rb +15 -0
- data/example/ex23.rb +20 -0
- data/example/ex24.rb +35 -0
- data/example/example_helper.rb +51 -0
- data/example/sample_service.rb +162 -0
- data/example/unsafe_service.rb +12 -0
- data/hack_night/README.txt +18 -0
- data/hack_night/exercise/prob-1.rb +18 -0
- data/hack_night/exercise/prob-2.rb +21 -0
- data/hack_night/exercise/prob-3.rb +16 -0
- data/hack_night/exercise/prob-4.rb +36 -0
- data/hack_night/exercise/prob-5.rb +36 -0
- data/hack_night/exercise/prob-6.rb +95 -0
- data/hack_night/exercise/prob-7.rb +34 -0
- data/hack_night/solution/math_service.rb +11 -0
- data/hack_night/solution/prob-1.rb +12 -0
- data/hack_night/solution/prob-2.rb +15 -0
- data/hack_night/solution/prob-3.rb +17 -0
- data/hack_night/solution/prob-4.rb +37 -0
- data/hack_night/solution/prob-5.rb +21 -0
- data/hack_night/solution/prob-6.rb +33 -0
- data/hack_night/solution/prob-7.rb +36 -0
- data/lab/phony_proc.rb +31 -0
- data/lib/asir.rb +253 -0
- data/lib/asir/additional_data.rb +25 -0
- data/lib/asir/channel.rb +130 -0
- data/lib/asir/client.rb +111 -0
- data/lib/asir/code_block.rb +57 -0
- data/lib/asir/code_more.rb +50 -0
- data/lib/asir/coder.rb +26 -0
- data/lib/asir/coder/base64.rb +19 -0
- data/lib/asir/coder/chain.rb +30 -0
- data/lib/asir/coder/identity.rb +23 -0
- data/lib/asir/coder/json.rb +30 -0
- data/lib/asir/coder/marshal.rb +17 -0
- data/lib/asir/coder/null.rb +23 -0
- data/lib/asir/coder/proc.rb +22 -0
- data/lib/asir/coder/sign.rb +48 -0
- data/lib/asir/coder/xml.rb +213 -0
- data/lib/asir/coder/yaml.rb +33 -0
- data/lib/asir/coder/zlib.rb +21 -0
- data/lib/asir/configuration.rb +32 -0
- data/lib/asir/error.rb +34 -0
- data/lib/asir/identity.rb +36 -0
- data/lib/asir/initialization.rb +23 -0
- data/lib/asir/log.rb +82 -0
- data/lib/asir/main.rb +396 -0
- data/lib/asir/message.rb +31 -0
- data/lib/asir/message/delay.rb +35 -0
- data/lib/asir/object_resolving.rb +15 -0
- data/lib/asir/result.rb +39 -0
- data/lib/asir/retry_behavior.rb +54 -0
- data/lib/asir/transport.rb +241 -0
- data/lib/asir/transport/beanstalk.rb +217 -0
- data/lib/asir/transport/broadcast.rb +34 -0
- data/lib/asir/transport/buffer.rb +115 -0
- data/lib/asir/transport/composite.rb +19 -0
- data/lib/asir/transport/connection_oriented.rb +180 -0
- data/lib/asir/transport/delay.rb +38 -0
- data/lib/asir/transport/delegation.rb +53 -0
- data/lib/asir/transport/fallback.rb +36 -0
- data/lib/asir/transport/file.rb +88 -0
- data/lib/asir/transport/http.rb +54 -0
- data/lib/asir/transport/local.rb +21 -0
- data/lib/asir/transport/null.rb +14 -0
- data/lib/asir/transport/payload_io.rb +52 -0
- data/lib/asir/transport/rack.rb +73 -0
- data/lib/asir/transport/retry.rb +41 -0
- data/lib/asir/transport/stream.rb +35 -0
- data/lib/asir/transport/subprocess.rb +30 -0
- data/lib/asir/transport/tcp_socket.rb +34 -0
- data/lib/asir/transport/webrick.rb +50 -0
- data/lib/asir/transport/zmq.rb +110 -0
- data/lib/asir/uuid.rb +32 -0
- data/lib/asir/version.rb +3 -0
- data/spec/const_get_speed_spec.rb +33 -0
- data/spec/debug_helper.rb +20 -0
- data/spec/example_spec.rb +88 -0
- data/spec/json_spec.rb +128 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/xml_spec.rb +144 -0
- data/stylesheets/slides.css +105 -0
- metadata +173 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
require 'asir'
|
|
2
|
+
require 'asir/object_resolving'
|
|
3
|
+
gem 'libxml-ruby'
|
|
4
|
+
require 'xml'
|
|
5
|
+
|
|
6
|
+
module ASIR
|
|
7
|
+
class Coder
|
|
8
|
+
# !SLIDE
|
|
9
|
+
# XML
|
|
10
|
+
#
|
|
11
|
+
# Encode/Decode objects as XML.
|
|
12
|
+
class XML < self
|
|
13
|
+
class Error < ::ASIR::Error
|
|
14
|
+
class BadIdref < self; end
|
|
15
|
+
end
|
|
16
|
+
def _encode obj
|
|
17
|
+
@stream = ''
|
|
18
|
+
@dom_id_map = { }
|
|
19
|
+
@dom_id = 0
|
|
20
|
+
@cls_tag_map = { }
|
|
21
|
+
encode_dom obj
|
|
22
|
+
@stream
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def _decode obj
|
|
26
|
+
@stream = obj
|
|
27
|
+
@decoder ||= DECODER; @decoder_object = nil
|
|
28
|
+
@dom_id_map = { }
|
|
29
|
+
@dom_id = 0
|
|
30
|
+
@cls_tag_map = { }
|
|
31
|
+
@parser = ::XML::Parser.string(@stream)
|
|
32
|
+
@dom = @parser.parse
|
|
33
|
+
decode_dom @dom.root
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def encode_dom obj
|
|
37
|
+
if dom_id = @dom_id_map[obj.object_id]
|
|
38
|
+
tag_obj(obj, nil, :idref => dom_id.first)
|
|
39
|
+
else
|
|
40
|
+
_encode_dom obj
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def _encode_dom obj
|
|
45
|
+
case obj
|
|
46
|
+
when NilClass, TrueClass, FalseClass
|
|
47
|
+
tag_obj(obj)
|
|
48
|
+
when Numeric
|
|
49
|
+
tag_obj(obj, nil, :v => obj.to_s)
|
|
50
|
+
when Symbol
|
|
51
|
+
tag_obj(obj) do
|
|
52
|
+
@stream << obj.to_s
|
|
53
|
+
end
|
|
54
|
+
when String
|
|
55
|
+
tag_obj(obj, :id) do
|
|
56
|
+
@stream << obj.to_s
|
|
57
|
+
end
|
|
58
|
+
when Array
|
|
59
|
+
tag_obj(obj, :id) do
|
|
60
|
+
obj.each do | elem |
|
|
61
|
+
encode_dom elem
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
when Hash
|
|
65
|
+
tag_obj(obj, :id) do
|
|
66
|
+
obj.each do | key, val |
|
|
67
|
+
encode_dom key
|
|
68
|
+
encode_dom val
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
else
|
|
72
|
+
tag_obj(obj, :id) do
|
|
73
|
+
obj.instance_variables.each do | attr |
|
|
74
|
+
val = obj.instance_variable_get(attr)
|
|
75
|
+
key = attr.to_s.sub(/^@/, '')
|
|
76
|
+
tag(key) do
|
|
77
|
+
encode_dom val
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def tag_obj obj, with_id = false, attrs = nil
|
|
85
|
+
if block_given?
|
|
86
|
+
tag(cls_tag(obj), with_id ? { with_id => map_obj_to_dom_id!(obj) } : nil) do
|
|
87
|
+
yield
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
tag(cls_tag(obj), attrs)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
CC = '::'.freeze; D = '.'.freeze
|
|
95
|
+
def cls_tag obj
|
|
96
|
+
obj = obj.class
|
|
97
|
+
@cls_tag_map[obj] ||= obj.name.gsub(CC, D).freeze
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def map_obj_to_dom_id! obj
|
|
101
|
+
if dom_id = @dom_id_map[obj.object_id]
|
|
102
|
+
dom_id.first
|
|
103
|
+
else
|
|
104
|
+
@dom_id_map[obj.object_id] = [ @dom_id += 1, obj ]
|
|
105
|
+
@dom_id
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
B = '<'.freeze; S = ' '.freeze; E = '>'.freeze; SE = '/>'.freeze
|
|
110
|
+
BS = '</'.freeze; A = '='.freeze
|
|
111
|
+
def tag tag, attrs = nil
|
|
112
|
+
tag = tag.to_s
|
|
113
|
+
@stream << B << tag << S
|
|
114
|
+
if attrs
|
|
115
|
+
attrs.each do | key, val |
|
|
116
|
+
@stream << key.to_s << A << val.to_s.inspect << S
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
if block_given?
|
|
120
|
+
@stream << E; yield; @stream << BS << tag << E
|
|
121
|
+
else
|
|
122
|
+
@stream << SE
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
################################################################
|
|
127
|
+
|
|
128
|
+
def decode_dom dom
|
|
129
|
+
if dom_id = dom.attributes[:idref]
|
|
130
|
+
unless obj = @dom_id_map[dom_id]
|
|
131
|
+
raise Error::BadIdref, "in element #{dom}"
|
|
132
|
+
end
|
|
133
|
+
obj
|
|
134
|
+
else
|
|
135
|
+
obj = _decode_dom(dom)
|
|
136
|
+
map_dom_id_to_obj! dom, obj if dom.attributes[:id]
|
|
137
|
+
obj
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def _decode_dom dom
|
|
142
|
+
cls_name = dom.name
|
|
143
|
+
decoder = @decoder[cls_name] ||
|
|
144
|
+
(@decoder_object ||= @decoder['Object'])
|
|
145
|
+
raise Error, "BUG: " unless decoder
|
|
146
|
+
decoder.call(self, dom)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
DECODER = {
|
|
150
|
+
'NilClass' => lambda { | _, dom | nil },
|
|
151
|
+
'TrueClass' => lambda { | _, dom | true },
|
|
152
|
+
'FalseClass' => lambda { | _, dom | false },
|
|
153
|
+
'String' => lambda { | _, dom | (dom.attributes[:v] || dom.content) },
|
|
154
|
+
'Symbol' => lambda { | _, dom | (dom.attributes[:v] || dom.content).to_sym },
|
|
155
|
+
'Integer' => lambda { | _, dom | (dom.attributes[:v] || dom.content).to_i },
|
|
156
|
+
'Float' => lambda { | _, dom | (dom.attributes[:v] || dom.content).to_f },
|
|
157
|
+
"Array" => lambda { | _, dom |
|
|
158
|
+
obj = [ ]
|
|
159
|
+
_.map_dom_id_to_obj! dom, obj
|
|
160
|
+
dom.each_element do | elem |
|
|
161
|
+
obj << _.decode_dom(elem)
|
|
162
|
+
end
|
|
163
|
+
obj
|
|
164
|
+
},
|
|
165
|
+
'Hash' => lambda { | _, dom |
|
|
166
|
+
obj = { }
|
|
167
|
+
_.map_dom_id_to_obj! dom, obj
|
|
168
|
+
key = nil
|
|
169
|
+
dom.each_element do | val |
|
|
170
|
+
if key
|
|
171
|
+
obj[_.decode_dom(key)] = _.decode_dom(val)
|
|
172
|
+
key = nil
|
|
173
|
+
else
|
|
174
|
+
key = val
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
obj
|
|
178
|
+
},
|
|
179
|
+
'Object' => lambda { | _, dom |
|
|
180
|
+
cls_name = dom.name
|
|
181
|
+
# $stderr.puts "cls_name = #{cls_name.inspect}"
|
|
182
|
+
cls = _.tag_cls(cls_name)
|
|
183
|
+
obj = cls.allocate
|
|
184
|
+
_.map_dom_id_to_obj! dom, obj
|
|
185
|
+
dom.each_element do | child |
|
|
186
|
+
key = child.name
|
|
187
|
+
val = _.decode_dom child.first
|
|
188
|
+
obj.instance_variable_set("@#{key}", val)
|
|
189
|
+
end
|
|
190
|
+
obj
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
DECODER['Fixnum'] = DECODER['Bignum'] = DECODER['Integer']
|
|
194
|
+
|
|
195
|
+
def map_dom_id_to_obj! dom, obj
|
|
196
|
+
dom_id = dom.attributes[:id]
|
|
197
|
+
debugger unless dom_id
|
|
198
|
+
raise Error, "no :id attribute in #{dom}" unless dom_id
|
|
199
|
+
if (other_obj = @dom_id_map[dom_id]) and other_obj.object_id != obj.object_id
|
|
200
|
+
raise Error, "BUG: :id #{dom_id} already used for #{other_obj.class.name} #{other_obj.inspect}"
|
|
201
|
+
end
|
|
202
|
+
@dom_id_map[dom_id] = obj
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
include ObjectResolving
|
|
206
|
+
def tag_cls cls_name
|
|
207
|
+
@cls_tag_map[cls_name.freeze] ||= resolve_object(cls_name.gsub('.', '::'))
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|
|
211
|
+
# !SLIDE END
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module ASIR
|
|
4
|
+
class Coder
|
|
5
|
+
# !SLIDE
|
|
6
|
+
# YAML Coder
|
|
7
|
+
# Use YAML for encode/decode.
|
|
8
|
+
class Yaml < self
|
|
9
|
+
def _encode obj
|
|
10
|
+
case obj
|
|
11
|
+
when Message, Result
|
|
12
|
+
obj = obj.encode_more!
|
|
13
|
+
end
|
|
14
|
+
::YAML::dump(obj)
|
|
15
|
+
rescue ::Exception
|
|
16
|
+
require 'pp'
|
|
17
|
+
msg = "#{self}: failed to encode: #{$!.inspect}:\n #{PP.pp(obj, '')}"
|
|
18
|
+
$stderr.puts msg
|
|
19
|
+
raise Error, msg
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def _decode obj
|
|
23
|
+
case obj = ::YAML::load(obj)
|
|
24
|
+
when Message, Result
|
|
25
|
+
obj.decode_more!
|
|
26
|
+
else
|
|
27
|
+
obj
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end # class
|
|
31
|
+
end # class
|
|
32
|
+
end # module
|
|
33
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'asir'
|
|
2
|
+
|
|
3
|
+
require 'zlib'
|
|
4
|
+
|
|
5
|
+
module ASIR
|
|
6
|
+
class Coder
|
|
7
|
+
class Zlib < self
|
|
8
|
+
attr_accessor :compression_level
|
|
9
|
+
|
|
10
|
+
def _encode obj
|
|
11
|
+
raise TypeError unless String === obj
|
|
12
|
+
::Zlib::Deflate.deflate(obj, @compression_level || ::Zlib::DEFAULT_COMPRESSION)
|
|
13
|
+
end
|
|
14
|
+
def _decode obj
|
|
15
|
+
raise TypeError unless String === obj
|
|
16
|
+
::Zlib::Inflate.inflate(obj)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module ASIR
|
|
2
|
+
IDENTITY_PROC = lambda { | x | x }
|
|
3
|
+
module Configuration
|
|
4
|
+
def self.included target
|
|
5
|
+
super
|
|
6
|
+
target.extend ClassMethods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Global default config_proc
|
|
10
|
+
def self.config_proc_hash
|
|
11
|
+
@@config_proc_hash ||= { }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module ClassMethods
|
|
15
|
+
def config_proc
|
|
16
|
+
ASIR::Configuration.config_proc_hash[self]
|
|
17
|
+
end
|
|
18
|
+
def config_proc= x
|
|
19
|
+
ASIR::Configuration.config_proc_hash[self] = x
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize *args
|
|
24
|
+
super
|
|
25
|
+
ch = ASIR::Configuration.config_proc_hash
|
|
26
|
+
(self.class.ancestors.map{|m| ch[m]}.compact.first ||
|
|
27
|
+
ch[nil] ||
|
|
28
|
+
IDENTITY_PROC
|
|
29
|
+
).call(self)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/asir/error.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module ASIR
|
|
2
|
+
# Generic API error.
|
|
3
|
+
class Error < ::Exception
|
|
4
|
+
# Subclass should override method.
|
|
5
|
+
class SubclassResponsibility < self; end
|
|
6
|
+
|
|
7
|
+
# Unsupported Feature.
|
|
8
|
+
class Unsupported < self; end
|
|
9
|
+
|
|
10
|
+
# Requested Stop.
|
|
11
|
+
class Terminate < self; end
|
|
12
|
+
|
|
13
|
+
# Unforwardable Exception.
|
|
14
|
+
#
|
|
15
|
+
# This encapsulates an Exception that should never be
|
|
16
|
+
# forwarded and re-thrown directly in the client.
|
|
17
|
+
# E.g.: SystemExit, Interrupt.
|
|
18
|
+
class Unforwardable < self
|
|
19
|
+
attr_accessor :original
|
|
20
|
+
def initialize msg, original = nil, *args
|
|
21
|
+
if ::Exception === msg
|
|
22
|
+
original ||= msg
|
|
23
|
+
msg = "#{original.class.name} #{msg.message}"
|
|
24
|
+
end
|
|
25
|
+
@original = original
|
|
26
|
+
super(msg)
|
|
27
|
+
self.set_backtrace original && original.backtrace
|
|
28
|
+
end
|
|
29
|
+
def self.unforwardable; @@unforwardable; end
|
|
30
|
+
def self.unforwardable= x; @@unforwardable = x; end
|
|
31
|
+
@@unforwardable ||= [ ::SystemExit, ::Interrupt ]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'asir/uuid'
|
|
2
|
+
require 'thread' # Mutex
|
|
3
|
+
|
|
4
|
+
module ASIR
|
|
5
|
+
# !SLIDE
|
|
6
|
+
# Message Identity
|
|
7
|
+
#
|
|
8
|
+
module Identity
|
|
9
|
+
attr_accessor :identifier, :timestamp
|
|
10
|
+
|
|
11
|
+
# Optional: Opaque data about the Client that created the Message.
|
|
12
|
+
attr_accessor :client
|
|
13
|
+
|
|
14
|
+
# Optional: Opaque data about the Service that handled the Result.
|
|
15
|
+
attr_accessor :server
|
|
16
|
+
|
|
17
|
+
# Creates a thread-safe unique identifier.
|
|
18
|
+
def create_identifier!
|
|
19
|
+
@identifier ||=
|
|
20
|
+
@@identifier_mutex.synchronize do
|
|
21
|
+
if @@uuid_pid != $$
|
|
22
|
+
@@uuid_pid = $$
|
|
23
|
+
@@uuid = nil
|
|
24
|
+
end
|
|
25
|
+
"#{@@counter += 1}-#{@@uuid ||= ::ASIR::UUID.generate}".freeze
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
@@counter ||= 0; @@uuid ||= nil; @@uuid_pid = nil; @@identifier_mutex ||= Mutex.new
|
|
29
|
+
|
|
30
|
+
# Creates a timestamp.
|
|
31
|
+
def create_timestamp!
|
|
32
|
+
@timestamp ||=
|
|
33
|
+
::Time.now.gmtime
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
module ASIR
|
|
3
|
+
# !SLIDE
|
|
4
|
+
# Object Initialization
|
|
5
|
+
#
|
|
6
|
+
# Support initialization by Hash.
|
|
7
|
+
#
|
|
8
|
+
# E.g.:
|
|
9
|
+
# Foo.new(:bar => 1, :baz => 2)
|
|
10
|
+
# ->
|
|
11
|
+
# obj = Foo.new; obj.bar = 1; obj.baz = 2; obj
|
|
12
|
+
module Initialization
|
|
13
|
+
def initialize opts = nil
|
|
14
|
+
opts ||= EMPTY_HASH
|
|
15
|
+
initialize_before_opts if respond_to? :initialize_before_opts
|
|
16
|
+
opts.each do | k, v |
|
|
17
|
+
send(:"#{k}=", v)
|
|
18
|
+
end
|
|
19
|
+
initialize_after_opts if respond_to? :initialize_after_opts
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
data/lib/asir/log.rb
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module ASIR
|
|
2
|
+
# !SLIDE
|
|
3
|
+
# Diagnostic Logging
|
|
4
|
+
#
|
|
5
|
+
# Logging mixin.
|
|
6
|
+
module Log
|
|
7
|
+
attr_accessor :_logger
|
|
8
|
+
|
|
9
|
+
def self.included target
|
|
10
|
+
super
|
|
11
|
+
target.send(:extend, ClassMethods)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
@@enabled = false
|
|
15
|
+
def self.enabled
|
|
16
|
+
@@enabled
|
|
17
|
+
end
|
|
18
|
+
def self.enabled= x
|
|
19
|
+
@@enabled = x
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module ClassMethods
|
|
23
|
+
def _log_enabled= x
|
|
24
|
+
(Thread.current[:'ASIR::Log.enabled'] ||= { })[self] = x
|
|
25
|
+
end
|
|
26
|
+
def _log_enabled?
|
|
27
|
+
(Thread.current[:'ASIR::Log.enabled'] ||= { })[self]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def _log_enabled= x
|
|
32
|
+
@_log_enabled = x
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def _log_enabled?
|
|
36
|
+
ASIR::Log.enabled ||
|
|
37
|
+
@_log_enabled ||
|
|
38
|
+
self.class._log_enabled?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def _log msg = nil
|
|
42
|
+
return unless _log_enabled?
|
|
43
|
+
msg ||= yield if block_given?
|
|
44
|
+
msg = String === msg ? msg : _log_format(msg)
|
|
45
|
+
msg = " #{$$} #{Module === self ? self : self.class} #{msg}"
|
|
46
|
+
case @_logger
|
|
47
|
+
when Proc
|
|
48
|
+
@_logger.call msg
|
|
49
|
+
when IO
|
|
50
|
+
@_logger.puts msg
|
|
51
|
+
else
|
|
52
|
+
$stderr.puts msg
|
|
53
|
+
end
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def _log_result msg
|
|
58
|
+
_log {
|
|
59
|
+
msg = String === msg ? msg : _log_format(msg);
|
|
60
|
+
"#{msg} => ..." }
|
|
61
|
+
result = yield
|
|
62
|
+
_log { "#{msg} => \n #{result.inspect}" }
|
|
63
|
+
result
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def _log_format obj
|
|
67
|
+
case obj
|
|
68
|
+
when Exception
|
|
69
|
+
msg = "#{obj.inspect}"
|
|
70
|
+
msg << "\n #{obj.backtrace * "\n "}" if false
|
|
71
|
+
msg
|
|
72
|
+
when Array
|
|
73
|
+
obj.map { | x | _log_format x } * ", "
|
|
74
|
+
else
|
|
75
|
+
obj.inspect
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end # module
|
|
79
|
+
end # module
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|