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.
Files changed (121) hide show
  1. data/.gitignore +11 -0
  2. data/Gemfile +16 -0
  3. data/README.textile +50 -0
  4. data/Rakefile +83 -0
  5. data/VERSION +1 -0
  6. data/asir.gemspec +36 -0
  7. data/asir.riterate.yml +114 -0
  8. data/bin/asir +6 -0
  9. data/doc/Rakefile +8 -0
  10. data/doc/asir-sequence.pic +84 -0
  11. data/doc/asir-sequence.svg +1559 -0
  12. data/doc/sequence.pic +430 -0
  13. data/example/asir_control.sh +24 -0
  14. data/example/asir_control_client_http.rb +14 -0
  15. data/example/asir_control_client_zmq.rb +15 -0
  16. data/example/config/asir_config.rb +63 -0
  17. data/example/delayed_service.rb +15 -0
  18. data/example/ex01.rb +12 -0
  19. data/example/ex02.rb +12 -0
  20. data/example/ex03.rb +19 -0
  21. data/example/ex04.rb +33 -0
  22. data/example/ex05.rb +16 -0
  23. data/example/ex06.rb +26 -0
  24. data/example/ex07.rb +28 -0
  25. data/example/ex08.rb +30 -0
  26. data/example/ex09.rb +25 -0
  27. data/example/ex10.rb +24 -0
  28. data/example/ex11.rb +48 -0
  29. data/example/ex12.rb +34 -0
  30. data/example/ex13.rb +35 -0
  31. data/example/ex14.rb +30 -0
  32. data/example/ex15.rb +13 -0
  33. data/example/ex16.rb +33 -0
  34. data/example/ex17.rb +41 -0
  35. data/example/ex18.rb +62 -0
  36. data/example/ex19.rb +32 -0
  37. data/example/ex20.rb +28 -0
  38. data/example/ex21.rb +28 -0
  39. data/example/ex22.rb +15 -0
  40. data/example/ex23.rb +20 -0
  41. data/example/ex24.rb +35 -0
  42. data/example/example_helper.rb +51 -0
  43. data/example/sample_service.rb +162 -0
  44. data/example/unsafe_service.rb +12 -0
  45. data/hack_night/README.txt +18 -0
  46. data/hack_night/exercise/prob-1.rb +18 -0
  47. data/hack_night/exercise/prob-2.rb +21 -0
  48. data/hack_night/exercise/prob-3.rb +16 -0
  49. data/hack_night/exercise/prob-4.rb +36 -0
  50. data/hack_night/exercise/prob-5.rb +36 -0
  51. data/hack_night/exercise/prob-6.rb +95 -0
  52. data/hack_night/exercise/prob-7.rb +34 -0
  53. data/hack_night/solution/math_service.rb +11 -0
  54. data/hack_night/solution/prob-1.rb +12 -0
  55. data/hack_night/solution/prob-2.rb +15 -0
  56. data/hack_night/solution/prob-3.rb +17 -0
  57. data/hack_night/solution/prob-4.rb +37 -0
  58. data/hack_night/solution/prob-5.rb +21 -0
  59. data/hack_night/solution/prob-6.rb +33 -0
  60. data/hack_night/solution/prob-7.rb +36 -0
  61. data/lab/phony_proc.rb +31 -0
  62. data/lib/asir.rb +253 -0
  63. data/lib/asir/additional_data.rb +25 -0
  64. data/lib/asir/channel.rb +130 -0
  65. data/lib/asir/client.rb +111 -0
  66. data/lib/asir/code_block.rb +57 -0
  67. data/lib/asir/code_more.rb +50 -0
  68. data/lib/asir/coder.rb +26 -0
  69. data/lib/asir/coder/base64.rb +19 -0
  70. data/lib/asir/coder/chain.rb +30 -0
  71. data/lib/asir/coder/identity.rb +23 -0
  72. data/lib/asir/coder/json.rb +30 -0
  73. data/lib/asir/coder/marshal.rb +17 -0
  74. data/lib/asir/coder/null.rb +23 -0
  75. data/lib/asir/coder/proc.rb +22 -0
  76. data/lib/asir/coder/sign.rb +48 -0
  77. data/lib/asir/coder/xml.rb +213 -0
  78. data/lib/asir/coder/yaml.rb +33 -0
  79. data/lib/asir/coder/zlib.rb +21 -0
  80. data/lib/asir/configuration.rb +32 -0
  81. data/lib/asir/error.rb +34 -0
  82. data/lib/asir/identity.rb +36 -0
  83. data/lib/asir/initialization.rb +23 -0
  84. data/lib/asir/log.rb +82 -0
  85. data/lib/asir/main.rb +396 -0
  86. data/lib/asir/message.rb +31 -0
  87. data/lib/asir/message/delay.rb +35 -0
  88. data/lib/asir/object_resolving.rb +15 -0
  89. data/lib/asir/result.rb +39 -0
  90. data/lib/asir/retry_behavior.rb +54 -0
  91. data/lib/asir/transport.rb +241 -0
  92. data/lib/asir/transport/beanstalk.rb +217 -0
  93. data/lib/asir/transport/broadcast.rb +34 -0
  94. data/lib/asir/transport/buffer.rb +115 -0
  95. data/lib/asir/transport/composite.rb +19 -0
  96. data/lib/asir/transport/connection_oriented.rb +180 -0
  97. data/lib/asir/transport/delay.rb +38 -0
  98. data/lib/asir/transport/delegation.rb +53 -0
  99. data/lib/asir/transport/fallback.rb +36 -0
  100. data/lib/asir/transport/file.rb +88 -0
  101. data/lib/asir/transport/http.rb +54 -0
  102. data/lib/asir/transport/local.rb +21 -0
  103. data/lib/asir/transport/null.rb +14 -0
  104. data/lib/asir/transport/payload_io.rb +52 -0
  105. data/lib/asir/transport/rack.rb +73 -0
  106. data/lib/asir/transport/retry.rb +41 -0
  107. data/lib/asir/transport/stream.rb +35 -0
  108. data/lib/asir/transport/subprocess.rb +30 -0
  109. data/lib/asir/transport/tcp_socket.rb +34 -0
  110. data/lib/asir/transport/webrick.rb +50 -0
  111. data/lib/asir/transport/zmq.rb +110 -0
  112. data/lib/asir/uuid.rb +32 -0
  113. data/lib/asir/version.rb +3 -0
  114. data/spec/const_get_speed_spec.rb +33 -0
  115. data/spec/debug_helper.rb +20 -0
  116. data/spec/example_spec.rb +88 -0
  117. data/spec/json_spec.rb +128 -0
  118. data/spec/spec_helper.rb +3 -0
  119. data/spec/xml_spec.rb +144 -0
  120. data/stylesheets/slides.css +105 -0
  121. 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
@@ -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
+
@@ -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
+