vigilem-core 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/lib/vigilem/core.rb +9 -0
  3. data/lib/vigilem/core/abstract_device.rb +97 -0
  4. data/lib/vigilem/core/adapters.rb +2 -0
  5. data/lib/vigilem/core/adapters/adapter.rb +57 -0
  6. data/lib/vigilem/core/adapters/basic_adapter.rb +43 -0
  7. data/lib/vigilem/core/adapters/buffered_adapter.rb +28 -0
  8. data/lib/vigilem/core/buffer.rb +151 -0
  9. data/lib/vigilem/core/buffer_handler.rb +95 -0
  10. data/lib/vigilem/core/default_buffer.rb +45 -0
  11. data/lib/vigilem/core/demultiplexer.rb +225 -0
  12. data/lib/vigilem/core/device.rb +43 -0
  13. data/lib/vigilem/core/event_handler.rb +156 -0
  14. data/lib/vigilem/core/eventable.rb +80 -0
  15. data/lib/vigilem/core/hooks.rb +36 -0
  16. data/lib/vigilem/core/hooks/callback.rb +66 -0
  17. data/lib/vigilem/core/hooks/callback_proc.rb +25 -0
  18. data/lib/vigilem/core/hooks/conditional_hook.rb +62 -0
  19. data/lib/vigilem/core/hooks/hook.rb +193 -0
  20. data/lib/vigilem/core/hooks/inheritable.rb +24 -0
  21. data/lib/vigilem/core/hooks/meta_callback.rb +53 -0
  22. data/lib/vigilem/core/hooks/utils.rb +23 -0
  23. data/lib/vigilem/core/hub.rb +50 -0
  24. data/lib/vigilem/core/input_system_handler.rb +55 -0
  25. data/lib/vigilem/core/lockable_pipeline_component.rb +30 -0
  26. data/lib/vigilem/core/multiplexer.rb +168 -0
  27. data/lib/vigilem/core/pipeline.rb +68 -0
  28. data/lib/vigilem/core/stat.rb +121 -0
  29. data/lib/vigilem/core/system.rb +9 -0
  30. data/lib/vigilem/core/system/check.rb +33 -0
  31. data/lib/vigilem/core/transfer_agent.rb +67 -0
  32. data/lib/vigilem/core/version.rb +5 -0
  33. data/spec/bug_notes.txt +12 -0
  34. data/spec/given_helper.rb +12 -0
  35. data/spec/spec_helper.rb +7 -0
  36. data/spec/vigilem/core/abstract_device_spec.rb +103 -0
  37. data/spec/vigilem/core/adapters/adapter_spec.rb +28 -0
  38. data/spec/vigilem/core/adapters/basic_adapter_spec.rb +53 -0
  39. data/spec/vigilem/core/adapters/buffered_adapter_spec.rb +16 -0
  40. data/spec/vigilem/core/buffer_handler_spec.rb +51 -0
  41. data/spec/vigilem/core/buffer_spec.rb +236 -0
  42. data/spec/vigilem/core/default_buffer_spec.rb +17 -0
  43. data/spec/vigilem/core/demultiplexer_spec.rb +166 -0
  44. data/spec/vigilem/core/device_spec.rb +62 -0
  45. data/spec/vigilem/core/event_handler_spec.rb +134 -0
  46. data/spec/vigilem/core/hooks/callback_proc_spec.rb +66 -0
  47. data/spec/vigilem/core/hooks/hook_spec.rb +230 -0
  48. data/spec/vigilem/core/hooks/inheritable_spec.rb +19 -0
  49. data/spec/vigilem/core/hooks/meta_callback_spec.rb +69 -0
  50. data/spec/vigilem/core/hooks/utils_spec.rb +25 -0
  51. data/spec/vigilem/core/hooks_spec.rb +50 -0
  52. data/spec/vigilem/core/hub_spec.rb +51 -0
  53. data/spec/vigilem/core/input_system_handler_spec.rb +33 -0
  54. data/spec/vigilem/core/lockable_pipeline_component_spec.rb +19 -0
  55. data/spec/vigilem/core/multiplexer_spec.rb +113 -0
  56. data/spec/vigilem/core/pipeline_spec.rb +5 -0
  57. data/spec/vigilem/core/stat_spec.rb +63 -0
  58. data/spec/vigilem/core/system/check_spec.rb +24 -0
  59. data/spec/vigilem/core/system_spec.rb +29 -0
  60. data/spec/vigilem/core/transfer_agent_spec.rb +80 -0
  61. metadata +273 -0
@@ -0,0 +1,45 @@
1
+ require 'delegate'
2
+
3
+ require 'vigilem/core/buffer'
4
+
5
+ module Vigilem
6
+ module Core
7
+ #
8
+ class DefaultBuffer < ::SimpleDelegator
9
+ include Buffer
10
+
11
+ #
12
+ # @param [#slice!] type
13
+ def initialize(type=[])
14
+ super(type)
15
+ end
16
+
17
+ # like new except type is not optional
18
+ # and passes through an object that is
19
+ # already of self type
20
+ # @param type
21
+ # @return [DefaultBuffer]
22
+ def self.wrap(type)
23
+ if type.is_a? self
24
+ type
25
+ else
26
+ new(type)
27
+ end
28
+ end
29
+
30
+ #
31
+ # @param other_obj
32
+ # @return [TrueClass || FalseClass]
33
+ def ==(other_obj)
34
+ super(other_obj) ||
35
+ __getobj__ == other_obj.respond.__getobj__
36
+ end
37
+
38
+ #
39
+ # @return [String]
40
+ def inspect
41
+ "#<#{self.class}:0x#{object_id} #{super}>"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,225 @@
1
+ require 'observer'
2
+
3
+ require 'thread_safe'
4
+
5
+ require 'vigilem/support/core_ext'
6
+
7
+ require 'vigilem/support/obj_space'
8
+
9
+ require 'vigilem/support/lazy_simple_delegator'
10
+
11
+ require 'vigilem/core/multiplexer'
12
+
13
+ module Vigilem
14
+ module Core
15
+ # #shift's from input and distributes it to the
16
+ # observers
17
+ class Demultiplexer
18
+ include Observable
19
+
20
+ extend Support::ObjSpace
21
+
22
+ attr_accessor :input
23
+
24
+ alias_method :source, :input
25
+ alias_method :source=, :input=
26
+
27
+ #
28
+ # @param [Array<Array<observer_object, Hash{@see #add_observer}>>] observers
29
+ # @param [(Buffer) #slice!] input_source
30
+ def self.new(input_source=nil, observers=[])
31
+ obj_register(super(input_source, observers))
32
+ end
33
+
34
+ #
35
+ # @param [Array<Array<observer_object, Hash{@see #add_observer}>>] observers
36
+ # @param [(Buffer) #shift] input_source
37
+ def initialize(input_source=nil, observers=[])
38
+ @input = input_source
39
+
40
+ add_observers(observers)
41
+ end
42
+
43
+ # the peers without the Delegators
44
+ # @return [Array]
45
+ def observers
46
+ _observers.map {|obj| obj.respond(:peel) || obj }
47
+ end
48
+
49
+ alias_method :outputs, :observers
50
+
51
+ #
52
+ # @return [Array]
53
+ def _observers
54
+ (@observer_peers ||= ThreadSafe::Hash.new).keys
55
+ end
56
+
57
+ alias_method :_outputs, :_observers
58
+
59
+ # @see Observable#add_observer
60
+ # @param [Hash] event_opts
61
+ # @option :func
62
+ # @option :type [Integer]
63
+ # @option :types [Array<Integer>]
64
+ # @option :device_name [Regexp]
65
+ # @option :device_names [Array<Regexp>]
66
+ # @option :device [File]
67
+ # @option :devices [Array<File>]
68
+ # @return [Array] [event_opts]
69
+ def add_observer(observer, event_opts={})
70
+ observer = Support::LazySimpleDelegator.new(observer).use_strict_eql if observer.is_a? Array
71
+ _observers
72
+ unless observer.respond_to?(event_opts[:func] ||= :update)
73
+ raise NoMethodError, "observer does not respond to `#{func.to_s}'"
74
+ end
75
+ @observer_peers[observer] = event_opts
76
+ end
77
+
78
+ alias_method :add_output, :add_observer
79
+
80
+ # @see Observable#add_observer
81
+ # @param [Array<Array<observer_object, Hash{@see add_observer}>>]
82
+ # @return [Array]
83
+ def add_observers(observers_and_opts)
84
+ observers_and_opts.map do |(obs, hsh)|
85
+ add_observer(*[obs, hsh].compact)
86
+ end
87
+ end
88
+
89
+ alias_method :add_outputs, :add_observers
90
+
91
+ #
92
+ # @see Object#inspect
93
+ # @return [String]
94
+ def inspect
95
+ if input.is_a? Array # @todo switch from regex
96
+ super.gsub(/@input=.+?(\s+|>)/, "@input=#<#{input.class}:#{Support::Utils.inspect_id(input)} #{input}>\\1")
97
+ else
98
+ super
99
+ end
100
+ end
101
+
102
+ #
103
+ # @return [Monitor]
104
+ def semaphore
105
+ if defined? super
106
+ super
107
+ else
108
+ @semaphore ||= Monitor.new
109
+ end
110
+ end
111
+
112
+ # gets events from input and notifies_observers
113
+ # @param [Integer] max_number_of_events
114
+ # @return
115
+ def demux(max_number_of_events=1)
116
+ semaphore.synchronize {
117
+ events = input.shift(max_number_of_events)
118
+ changed
119
+ notify_observers(*events)
120
+ }
121
+ end
122
+
123
+ #
124
+ # @see Observable#notify_observers
125
+ # @param [Array]
126
+ # @return [TrueClass || FalseClass]
127
+ def notify_observers(*events)
128
+ if defined? @observer_state and @observer_state
129
+ if defined? @observer_peers
130
+ @observer_peers.each do |k, event_opts|
131
+ filtered = self.class.filter_events(events, event_opts)
132
+ k.send event_opts[:func], filtered unless filtered.empty?
133
+ end
134
+ end
135
+ @observer_state = false
136
+ end
137
+ end
138
+
139
+ alias_method :sweep, :notify_observers
140
+ alias_method :notify_outputs, :notify_observers
141
+
142
+ #
143
+ # @param [Array] events
144
+ # @param [Hash{@see #add_observer}] event_opts
145
+ # @return [Array]
146
+ def filter_events(events, event_opts)
147
+ self.class.filter_events(events, event_opts)
148
+ end
149
+
150
+ class << self
151
+
152
+ #
153
+ # @param base
154
+ # @return
155
+ def inherited(base)
156
+ base.extend Support::ObjSpace
157
+ end
158
+
159
+ #
160
+ # @param [Array<#metadata, #type>] events
161
+ # @param [Hash{@see #add_observer}] event_opts
162
+ # @return [Array]
163
+ def filter_events(events, event_opts)
164
+ events.select do |event|
165
+ opts = event_opts.select {|k,v| event_option_names.include? k }
166
+ if opts.empty?
167
+ event
168
+ else
169
+ opts.all? do |opt,v|
170
+ opt_vals = [v].flatten
171
+ case opt.to_s
172
+ when /^devices?$/
173
+ opt_vals.any? do |dev|
174
+ if (src = event.metadata[:source])
175
+ File.identical?(dev, src)
176
+ end
177
+ end
178
+ when /^device_names?$/
179
+ opt_vals.any? {|dev_name| event.metadata[:source].respond.name =~ dev_name }
180
+ when /^types?$/
181
+ opt_vals.any? {|ev_type| event.type == ev_type }
182
+ end
183
+ end
184
+
185
+ end # else
186
+
187
+ end
188
+ end
189
+
190
+ # like first_or_new
191
+ # @return [Demultiplexer]
192
+ def acquire(input_source=nil, observers=[], &block)
193
+ found = all.find(&block)
194
+ if found
195
+ found.add_observers(observers)
196
+ else
197
+ new(input_source, observers)
198
+ end
199
+ end
200
+
201
+ #
202
+ # @return [Hash]
203
+ def same_source_check
204
+ all.group_by do |dem|
205
+ dem.respond(:fileno) || dem
206
+ end.select {|k, v| v.size > 1 }
207
+ end
208
+
209
+ #
210
+ # @return [Array<Symbol>]
211
+ def event_option_names
212
+ @event_option_names ||= option_names - [:func]
213
+ end
214
+
215
+ #
216
+ # @return [Array<Symbol>]
217
+ def option_names
218
+ @options ||= [:func, :type, :types, :device_name, :device_names, :device, :devices]
219
+ end
220
+
221
+ end
222
+ end
223
+
224
+ end
225
+ end
@@ -0,0 +1,43 @@
1
+ require 'vigilem/core/abstract_device'
2
+
3
+ require 'vigilem/core/hooks'
4
+
5
+ require 'vigilem/core/system'
6
+
7
+ module Vigilem
8
+ module Core
9
+ #
10
+ # hooks for loading the pipeline
11
+ # errors when no :system_check has passed
12
+ # @todo more configurable facade so not all methods from
13
+ # underlying object get through
14
+ class Device < AbstractDevice
15
+
16
+ #
17
+ # @param [Array] args
18
+ # @param [Proc] config
19
+ # @return
20
+ def self.new(*args, &config)
21
+ if block_given?
22
+ (ret = Class.new(self)).instance_eval(&config)
23
+ ret
24
+ else
25
+ super(*args)
26
+ end
27
+ end
28
+
29
+ Hooks::ConditionalHook.new(:on_os, :type => :system_check) do
30
+ condition {|name_or_regex| System.check[:os].call(name_or_regex) }
31
+ end.bind(self)
32
+
33
+ Hooks::ConditionalHook.new(:on_input_system, :type => :system_check) do
34
+ condition {|name_or_regex| System.check[:input_system].call(name_or_regex) }
35
+ end.bind(self)
36
+
37
+ after_init do |dev|
38
+ raise 'Device not compatible on this system' unless dev.available?
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,156 @@
1
+ require 'forwardable'
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Vigilem
6
+ module Core
7
+ #
8
+ #
9
+ module EventHandler
10
+
11
+ extend Forwardable
12
+
13
+ extend ActiveSupport::Concern
14
+
15
+ #
16
+ #
17
+ module Utils
18
+
19
+ #
20
+ # @param [#to_s] namespace
21
+ # @return [String]
22
+ def snakecase_class_name(namespace)
23
+ namespace.to_s.split('::').last.snakecase
24
+ end
25
+
26
+ #
27
+ # @param [Symbol] sym
28
+ # @return [TrueClass || FalseClass]
29
+ def respond_to?(sym, include_all=false)
30
+ on_format?(sym.to_s) || super(sym, include_all)
31
+ end
32
+
33
+ # does the string passed in start with 'on_'
34
+ # @param [String] str
35
+ # @return [TrueClass || FalseClass]
36
+ def on_format?(str)
37
+ str.start_with?('on_')
38
+ end
39
+
40
+ # converts a "on_String" => :String
41
+ # @param [String] on_name
42
+ # @return [Symbol]
43
+ def type_from_on_format(on_name)
44
+ on_name.split('on_', 2).last.to_sym
45
+ end
46
+ end
47
+
48
+ include Utils
49
+ extend Utils
50
+
51
+ module ClassMethods
52
+
53
+ include Utils
54
+
55
+ # @todo Fuzzy is_a? Hash key lookup
56
+ # @return [Hash]
57
+ def type_handles
58
+ @type_handles ||= {}
59
+ end
60
+
61
+ #
62
+ # sets the default_handler, if called without a block, just
63
+ # assigns the default handler to a "default"
64
+ # @param [Proc] block
65
+ # @return [Proc]
66
+ def default_handler(&block)
67
+ type_handles.default = (block || lambda {|*args, &block| })
68
+ end
69
+
70
+ # @todo module_function
71
+ # configures how this event handler handles an event
72
+ # @param type
73
+ # @return [Proc] the block given/registered
74
+ def on(type, opts={}, &block)
75
+ type_name = snakecase_class_name(type)
76
+ on_method = send(:_define_register, type, type_name)
77
+ type_handles[type] = send(:_define_handler, type_name, &block)
78
+ on_method.call(&block)
79
+ end
80
+
81
+ alias_method :register_handle, :on
82
+
83
+ private
84
+
85
+ # defines `on_#{event_type}'
86
+ # @param type
87
+ # @param [String] type_name
88
+ # @param [Proc] block
89
+ # @return [Method]
90
+ def _define_register(type, type_name)
91
+ define_singleton_method(on_method_name = :"on_#{type_name}") {|opts={}, &blk| type_handles[type] = blk }
92
+ define_method(on_method_name) {|opts={}, &blk| self.class.send(on_method_name, opts, &blk) }
93
+ method(on_method_name)
94
+ end
95
+
96
+ # defines `handle_#{event_type}'
97
+ # @param [String] type
98
+ # @param [Proc] block
99
+ # @return [Proc]
100
+ def _define_handler(type_name, &block)
101
+ define_method(handler_name = :"handle_#{type_name}", &block)
102
+ block
103
+ end
104
+
105
+ end
106
+
107
+ #
108
+ # @return [Hash]
109
+ def type_handles
110
+ self.class.type_handles
111
+ end
112
+
113
+ # to trigger the handling, either use handle(event, opts={}) or handle_#{type}
114
+ # configures how this event handler handles an event
115
+ # @param [#to_s] type
116
+ # @return [Proc] the block given/registered
117
+ def on(type, &block)
118
+ define_singleton_method(on_method_name = :"on_#{class_name = snakecase_class_name(type)}") {|&blk| type_handles[type] = blk }
119
+ ret = send on_method_name, &block
120
+ define_singleton_method(handler_name = :"handle_#{class_name}", &type_handles[type])
121
+ ret
122
+ end
123
+ alias_method :register_handle, :on
124
+
125
+ #
126
+ # @param event, the event to handle
127
+ # @param [Array]
128
+ # @return results of the Proc registered to the type_handless
129
+ def handle(event, *args, &block)
130
+ if handler = type_handles[event.class]
131
+ handler.call(event, *args, &block)
132
+ end
133
+ end
134
+
135
+ #
136
+ # @param event, the event to handle
137
+ # @param [Array]
138
+ # @return results of the Proc registered to the type_handless
139
+ def handle!(event, *args, &block)
140
+ if ret = handle(event, *args, &block)
141
+ ret
142
+ else
143
+ raise NotImplementedError, "No handler found for #{key.class}:#{key},#{block} and no default handler set"
144
+ end
145
+ end
146
+
147
+ #
148
+ # @param [Proc]
149
+ # @return
150
+ def default_handler(&block)
151
+ self.class.default_handler(&block)
152
+ end
153
+
154
+ end
155
+ end
156
+ end