asir 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+