artoo 0.1.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 +25 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +144 -0
- data/Guardfile +15 -0
- data/LICENSE +13 -0
- data/README.md +97 -0
- data/Rakefile +11 -0
- data/api/assets/compass.rb +25 -0
- data/api/assets/javascripts/artoo/controllers/robot.js.coffee +27 -0
- data/api/assets/javascripts/artoo/routes.js.coffee +23 -0
- data/api/assets/javascripts/core.js.coffee +6 -0
- data/api/assets/javascripts/vendor/angular.min.js +161 -0
- data/api/assets/javascripts/vendor/bootstrap.min.js +6 -0
- data/api/assets/javascripts/vendor/jquery.min.js +5 -0
- data/api/assets/stylesheets/artoo/_core.css.scss +3 -0
- data/api/assets/stylesheets/artoo/_font-awesome.scss +534 -0
- data/api/assets/stylesheets/artoo/_variables.scss +8 -0
- data/api/assets/stylesheets/core.scss +70 -0
- data/api/public/core.css +9848 -0
- data/api/public/core.js +259 -0
- data/api/public/favicon.ico +0 -0
- data/api/public/font/FontAwesome.otf +0 -0
- data/api/public/font/fontawesome-webfont.eot +0 -0
- data/api/public/font/fontawesome-webfont.svg +284 -0
- data/api/public/font/fontawesome-webfont.ttf +0 -0
- data/api/public/font/fontawesome-webfont.woff +0 -0
- data/api/public/html5shiv.js +8 -0
- data/api/public/images/devices/ardrone.jpg +0 -0
- data/api/public/images/devices/arduino.jpg +0 -0
- data/api/public/images/devices/sphero.png +0 -0
- data/api/public/images/glyphicons-halflings-white.png +0 -0
- data/api/public/images/glyphicons-halflings.png +0 -0
- data/api/public/index.html +36 -0
- data/api/public/partials/robot-detail.html +111 -0
- data/api/public/partials/robot-device-detail.html +0 -0
- data/api/public/partials/robot-index.html +26 -0
- data/artoo.gemspec +21 -0
- data/bin/retry.sh +8 -0
- data/bin/sphero.sh +8 -0
- data/examples/ardrone.rb +12 -0
- data/examples/ardrone_nav.rb +22 -0
- data/examples/ardrone_nav_video.rb +33 -0
- data/examples/ardrone_video.rb +22 -0
- data/examples/conway_sphero.rb +65 -0
- data/examples/firmata.rb +13 -0
- data/examples/firmata_button.rb +9 -0
- data/examples/hello.rb +12 -0
- data/examples/hello_api.rb +9 -0
- data/examples/hello_api_multiple.rb +25 -0
- data/examples/hello_modular.rb +16 -0
- data/examples/hello_multiple.rb +22 -0
- data/examples/notifications.rb +9 -0
- data/examples/sphero.rb +11 -0
- data/examples/sphero_color.rb +13 -0
- data/examples/sphero_firmata.rb +17 -0
- data/examples/sphero_messages.rb +22 -0
- data/examples/sphero_multiple.rb +33 -0
- data/examples/wiiclassic.rb +94 -0
- data/lib/artoo.rb +3 -0
- data/lib/artoo/adaptors/adaptor.rb +54 -0
- data/lib/artoo/adaptors/ardrone.rb +32 -0
- data/lib/artoo/adaptors/ardrone_navigation.rb +26 -0
- data/lib/artoo/adaptors/ardrone_video.rb +27 -0
- data/lib/artoo/adaptors/firmata.rb +25 -0
- data/lib/artoo/adaptors/loopback.rb +8 -0
- data/lib/artoo/adaptors/sphero.rb +46 -0
- data/lib/artoo/api.rb +48 -0
- data/lib/artoo/api_route_helpers.rb +197 -0
- data/lib/artoo/connection.rb +70 -0
- data/lib/artoo/delegator.rb +49 -0
- data/lib/artoo/device.rb +61 -0
- data/lib/artoo/device_event_client.rb +27 -0
- data/lib/artoo/drivers/ardrone.rb +9 -0
- data/lib/artoo/drivers/ardrone_navigation.rb +21 -0
- data/lib/artoo/drivers/ardrone_video.rb +22 -0
- data/lib/artoo/drivers/button.rb +40 -0
- data/lib/artoo/drivers/driver.rb +48 -0
- data/lib/artoo/drivers/led.rb +37 -0
- data/lib/artoo/drivers/passthru.rb +9 -0
- data/lib/artoo/drivers/pinger.rb +19 -0
- data/lib/artoo/drivers/pinger2.rb +18 -0
- data/lib/artoo/drivers/sphero.rb +57 -0
- data/lib/artoo/drivers/wiichuck.rb +29 -0
- data/lib/artoo/drivers/wiiclassic.rb +137 -0
- data/lib/artoo/main.rb +32 -0
- data/lib/artoo/master.rb +16 -0
- data/lib/artoo/port.rb +51 -0
- data/lib/artoo/robot.rb +299 -0
- data/lib/artoo/utility.rb +39 -0
- data/lib/artoo/version.rb +5 -0
- data/test/adaptors/adaptor_test.rb +18 -0
- data/test/adaptors/ardrone_test.rb +24 -0
- data/test/adaptors/firmata_test.rb +25 -0
- data/test/adaptors/loopback_test.rb +18 -0
- data/test/adaptors/sphero_test.rb +24 -0
- data/test/api_test.rb +61 -0
- data/test/artoo_test.rb +12 -0
- data/test/connection_test.rb +28 -0
- data/test/delegator_test.rb +71 -0
- data/test/device_test.rb +41 -0
- data/test/drivers/ardrone_navigation_test.rb +11 -0
- data/test/drivers/ardrone_test.rb +11 -0
- data/test/drivers/ardrone_video_test.rb +11 -0
- data/test/drivers/driver_test.rb +21 -0
- data/test/drivers/led_test.rb +52 -0
- data/test/drivers/sphero_test.rb +54 -0
- data/test/drivers/wiichuck_test.rb +11 -0
- data/test/port_test.rb +33 -0
- data/test/robot_test.rb +96 -0
- data/test/test_helper.rb +8 -0
- data/test/utility_test.rb +27 -0
- metadata +185 -0
data/lib/artoo/main.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'artoo/delegator'
|
|
2
|
+
require 'artoo/robot'
|
|
3
|
+
|
|
4
|
+
module Artoo
|
|
5
|
+
# Execution context for top-level robots
|
|
6
|
+
# DSL methods executed on main are delegated to this class like Sinatra
|
|
7
|
+
class MainRobot < Artoo::Robot
|
|
8
|
+
|
|
9
|
+
# we assume that the first file that requires 'artoo' is the
|
|
10
|
+
# app_file. all other path related options are calculated based
|
|
11
|
+
# on this path by default.
|
|
12
|
+
set :app_file, caller_files.first || $0
|
|
13
|
+
set :start_work, Proc.new { File.expand_path($0) == File.expand_path(app_file) }
|
|
14
|
+
|
|
15
|
+
# if run? && ARGV.any?
|
|
16
|
+
# require 'optparse'
|
|
17
|
+
# OptionParser.new { |op|
|
|
18
|
+
# op.on('-p port', 'set the port (default is 4567)') { |val| set :port, Integer(val) }
|
|
19
|
+
# op.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| set :bind, val }
|
|
20
|
+
# op.on('-e env', 'set the environment (default is development)') { |val| set :environment, val.to_sym }
|
|
21
|
+
# op.on('-s server', 'specify rack server/handler (default is thin)') { |val| set :server, val }
|
|
22
|
+
# op.on('-x', 'turn on the mutex lock (default is off)') { set :lock, true }
|
|
23
|
+
# }.parse!(ARGV.dup)
|
|
24
|
+
# end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
at_exit { MainRobot.work! if $!.nil? && MainRobot.start_work? }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# include would include the module in Object
|
|
31
|
+
# extend only extends the `main` object
|
|
32
|
+
extend Artoo::Delegator
|
data/lib/artoo/master.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Artoo
|
|
2
|
+
# The Artoo::Master class is a registered supervisor class to keep track
|
|
3
|
+
# of all the running robots
|
|
4
|
+
class Master
|
|
5
|
+
include Celluloid
|
|
6
|
+
attr_reader :robots
|
|
7
|
+
|
|
8
|
+
def initialize(bots)
|
|
9
|
+
@robots = bots
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_robot_by_name(name)
|
|
13
|
+
robots.find_all {|r| r.name == name}.first
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/artoo/port.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Artoo
|
|
2
|
+
# The Artoo::Port class represents port and/or host to be used to connect
|
|
3
|
+
# tp a specific individual hardware device.
|
|
4
|
+
class Port
|
|
5
|
+
attr_reader :port, :host
|
|
6
|
+
|
|
7
|
+
def initialize(data)
|
|
8
|
+
@is_tcp, @is_serial = false
|
|
9
|
+
parse(data)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def is_serial?
|
|
13
|
+
@is_serial == true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def is_tcp?
|
|
17
|
+
@is_tcp == true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
if is_serial?
|
|
22
|
+
port
|
|
23
|
+
else
|
|
24
|
+
"#{host}:#{port}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def parse(data)
|
|
31
|
+
# is TCP host/port?
|
|
32
|
+
if m = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})/.match(data)
|
|
33
|
+
@port = m[2]
|
|
34
|
+
@host = m[1]
|
|
35
|
+
@is_tcp = true
|
|
36
|
+
|
|
37
|
+
# is it a numeric port for localhost tcp?
|
|
38
|
+
elsif /^[0-9]{1,5}$/.match(data)
|
|
39
|
+
@port = data
|
|
40
|
+
@host = "localhost"
|
|
41
|
+
@is_tcp = true
|
|
42
|
+
|
|
43
|
+
# must be a serial port
|
|
44
|
+
else
|
|
45
|
+
@port = data
|
|
46
|
+
@host = nil
|
|
47
|
+
@is_serial = true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/artoo/robot.rb
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
require 'celluloid/io'
|
|
2
|
+
require 'multi_json'
|
|
3
|
+
|
|
4
|
+
require 'artoo/connection'
|
|
5
|
+
require 'artoo/device'
|
|
6
|
+
require 'artoo/api'
|
|
7
|
+
require 'artoo/master'
|
|
8
|
+
require 'artoo/port'
|
|
9
|
+
require 'artoo/utility'
|
|
10
|
+
|
|
11
|
+
module Artoo
|
|
12
|
+
# The most important class used by Artoo is Robot. This represents the primary
|
|
13
|
+
# interface for interacting with a collection of physical computing capabilities.
|
|
14
|
+
class Robot
|
|
15
|
+
include Celluloid
|
|
16
|
+
include Celluloid::Notifications
|
|
17
|
+
include Artoo::Utility
|
|
18
|
+
|
|
19
|
+
attr_reader :connections, :devices, :name
|
|
20
|
+
|
|
21
|
+
def initialize(params={})
|
|
22
|
+
@name = params[:name] || "Robot #{random_string}"
|
|
23
|
+
initialize_connections(params[:connections] || {})
|
|
24
|
+
initialize_devices(params[:devices] || {})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
attr_accessor :connection_types, :device_types, :working_code,
|
|
29
|
+
:use_api, :api_host, :api_port
|
|
30
|
+
|
|
31
|
+
# connection to some hardware that has one or more devices via some specific protocol
|
|
32
|
+
# Example:
|
|
33
|
+
# connection :arduino, :adaptor => :firmata, :port => '/dev/tty.usbmodemxxxxx'
|
|
34
|
+
def connection(name, params = {})
|
|
35
|
+
Celluloid::Logger.info "Registering connection '#{name}'..."
|
|
36
|
+
self.connection_types ||= []
|
|
37
|
+
self.connection_types << {:name => name}.merge(params)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# device that uses a connection to communicate
|
|
41
|
+
# Example:
|
|
42
|
+
# device :collision_detect, :driver => :switch, :pin => 3
|
|
43
|
+
def device(name, params = {})
|
|
44
|
+
Celluloid::Logger.info "Registering device '#{name}'..."
|
|
45
|
+
self.device_types ||= []
|
|
46
|
+
self.device_types << {:name => name}.merge(params)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# the work that needs to be performed
|
|
50
|
+
# Example:
|
|
51
|
+
# work do
|
|
52
|
+
# every(10.seconds) do
|
|
53
|
+
# puts "hello, world"
|
|
54
|
+
# end
|
|
55
|
+
# end
|
|
56
|
+
def work(&block)
|
|
57
|
+
Celluloid::Logger.info "Preparing work..."
|
|
58
|
+
self.working_code = block if block_given?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# activate RESTful api
|
|
62
|
+
# Example:
|
|
63
|
+
# api :host => '127.0.0.1', :port => '1234'
|
|
64
|
+
def api(params = {})
|
|
65
|
+
Celluloid::Logger.info "Registering api..."
|
|
66
|
+
self.use_api = true
|
|
67
|
+
self.api_host = params[:host] || '127.0.0.1'
|
|
68
|
+
self.api_port = params[:port] || '4321'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# work can be performed by either:
|
|
72
|
+
# an existing instance
|
|
73
|
+
# an array of existing instances
|
|
74
|
+
# or, a new instance can be created
|
|
75
|
+
def work!(robot=nil)
|
|
76
|
+
if robot.respond_to?(:work)
|
|
77
|
+
robots = [robot]
|
|
78
|
+
elsif robot.kind_of?(Array)
|
|
79
|
+
robots = robot
|
|
80
|
+
else
|
|
81
|
+
robots = [self.new]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
robots.each {|r| r.async.work}
|
|
85
|
+
|
|
86
|
+
Celluloid::Actor[:master] = Master.new(robots)
|
|
87
|
+
Celluloid::Actor[:api] = Api.new(self.api_host, self.api_port) if self.use_api
|
|
88
|
+
|
|
89
|
+
sleep # sleep main thread, and let the work commence!
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test?
|
|
93
|
+
ENV["ARTOO_TEST"] == 'true'
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Taken from Sinatra codebase
|
|
97
|
+
# Sets an option to the given value. If the value is a proc,
|
|
98
|
+
# the proc will be called every time the option is accessed.
|
|
99
|
+
def set(option, value = (not_set = true), ignore_setter = false, &block)
|
|
100
|
+
raise ArgumentError if block and !not_set
|
|
101
|
+
value, not_set = block, false if block
|
|
102
|
+
|
|
103
|
+
if not_set
|
|
104
|
+
raise ArgumentError unless option.respond_to?(:each)
|
|
105
|
+
option.each { |k,v| set(k, v) }
|
|
106
|
+
return self
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
if respond_to?("#{option}=") and not ignore_setter
|
|
110
|
+
return __send__("#{option}=", value)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
setter = proc { |val| set option, val, true }
|
|
114
|
+
getter = proc { value }
|
|
115
|
+
|
|
116
|
+
case value
|
|
117
|
+
when Proc
|
|
118
|
+
getter = value
|
|
119
|
+
when Symbol, Fixnum, FalseClass, TrueClass, NilClass
|
|
120
|
+
getter = value.inspect
|
|
121
|
+
when Hash
|
|
122
|
+
setter = proc do |val|
|
|
123
|
+
val = value.merge val if Hash === val
|
|
124
|
+
set option, val, true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
define_singleton_method("#{option}=", setter) if setter
|
|
129
|
+
define_singleton_method(option, getter) if getter
|
|
130
|
+
define_singleton_method("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
|
|
131
|
+
self
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Taken from Sinatra codebase
|
|
135
|
+
CALLERS_TO_IGNORE = [ # :nodoc:
|
|
136
|
+
/lib\/artoo.*\.rb$/, # artoo code
|
|
137
|
+
/^\(.*\)$/, # generated code
|
|
138
|
+
/rubygems\/custom_require\.rb$/, # rubygems require hacks
|
|
139
|
+
/active_support/, # active_support require hacks
|
|
140
|
+
/bundler(\/runtime)?\.rb/, # bundler require hacks
|
|
141
|
+
/<internal:/, # internal in ruby >= 1.9.2
|
|
142
|
+
/src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
# Taken from Sinatra codebase
|
|
146
|
+
# Like Kernel#caller but excluding certain magic entries and without
|
|
147
|
+
# line / method information; the resulting array contains filenames only.
|
|
148
|
+
def caller_files
|
|
149
|
+
cleaned_caller(1).flatten
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
private
|
|
153
|
+
|
|
154
|
+
# Taken from Sinatra codebase
|
|
155
|
+
def define_singleton_method(name, content = Proc.new)
|
|
156
|
+
# replace with call to singleton_class once we're 1.9 only
|
|
157
|
+
(class << self; self; end).class_eval do
|
|
158
|
+
undef_method(name) if method_defined? name
|
|
159
|
+
String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Taken from Sinatra codebase
|
|
164
|
+
# Like Kernel#caller but excluding certain magic entries
|
|
165
|
+
def cleaned_caller(keep = 3)
|
|
166
|
+
caller(1).
|
|
167
|
+
map { |line| line.split(/:(?=\d|in )/, 3)[0,keep] }.
|
|
168
|
+
reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def safe_name
|
|
173
|
+
name.gsub(' ', '_').downcase
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def api_host
|
|
177
|
+
self.class.api_host
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def api_port
|
|
181
|
+
self.class.api_port
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# start doing the work
|
|
185
|
+
def work
|
|
186
|
+
Logger.info "Starting work..."
|
|
187
|
+
make_connections
|
|
188
|
+
start_devices
|
|
189
|
+
current_instance.instance_eval(&working_code)
|
|
190
|
+
rescue Exception => e
|
|
191
|
+
Logger.error e.message
|
|
192
|
+
Logger.error e.backtrace.inspect
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def make_connections
|
|
196
|
+
result = false
|
|
197
|
+
future_connections = []
|
|
198
|
+
# block until all connections done
|
|
199
|
+
connections.each {|k, c| future_connections << c.future.connect}
|
|
200
|
+
future_connections.each {|v| result = v.value}
|
|
201
|
+
result
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def start_devices
|
|
205
|
+
result = false
|
|
206
|
+
future_devices = []
|
|
207
|
+
# block until all devices done
|
|
208
|
+
devices.each {|k, d| future_devices << d.future.start_device}
|
|
209
|
+
future_devices.each {|v| result = v.value}
|
|
210
|
+
result
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def disconnect
|
|
214
|
+
connections.each {|k, c| c.async.disconnect}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def default_connection
|
|
218
|
+
connections[connections.keys.first]
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def connection_types
|
|
222
|
+
current_class.connection_types ||= []
|
|
223
|
+
current_class.connection_types
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def device_types
|
|
227
|
+
current_class.device_types ||= []
|
|
228
|
+
current_class.device_types
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def working_code
|
|
232
|
+
current_class.working_code ||= proc {puts "No work defined."}
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Subscribe to an event from a device
|
|
236
|
+
def on(device, events={})
|
|
237
|
+
events.each do |k, v|
|
|
238
|
+
subscribe("#{safe_name}_#{device.name}_#{k}", create_proxy_method(k, v))
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Create an anonymous subscription method so we can wrap the
|
|
243
|
+
# subscription method fire into a valid method regardless
|
|
244
|
+
# of where it is defined
|
|
245
|
+
def create_proxy_method(k, v)
|
|
246
|
+
proxy_method_name(k).tap do |name|
|
|
247
|
+
self.class.send :define_method, name do |*args|
|
|
248
|
+
case v
|
|
249
|
+
when Symbol
|
|
250
|
+
self.send v.to_sym, *args
|
|
251
|
+
when Proc
|
|
252
|
+
v.call(*args)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# A simple loop to create a 'fake' anonymous method
|
|
259
|
+
def proxy_method_name(k)
|
|
260
|
+
begin
|
|
261
|
+
meth = "#{k}_#{Random.rand(999)}"
|
|
262
|
+
end while respond_to?(meth)
|
|
263
|
+
meth
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def to_hash
|
|
267
|
+
{:name => name,
|
|
268
|
+
:connections => connections.each_value.collect {|c|c.to_hash},
|
|
269
|
+
:devices => devices.each_value.collect {|d|d.to_hash}
|
|
270
|
+
}
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def as_json
|
|
274
|
+
MultiJson.dump(to_hash)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
private
|
|
278
|
+
|
|
279
|
+
def initialize_connections(params={})
|
|
280
|
+
@connections = {}
|
|
281
|
+
connection_types.each {|ct|
|
|
282
|
+
Logger.info "Initializing connection #{ct[:name].to_s}..."
|
|
283
|
+
cp = params[ct[:name]] || {}
|
|
284
|
+
c = Connection.new(ct.merge(cp).merge(:parent => current_instance))
|
|
285
|
+
@connections[ct[:name]] = c
|
|
286
|
+
}
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def initialize_devices(params={})
|
|
290
|
+
@devices = {}
|
|
291
|
+
device_types.each {|d|
|
|
292
|
+
Logger.info "Initializing device #{d[:name].to_s}..."
|
|
293
|
+
d = Device.new(d.merge(:parent => current_instance))
|
|
294
|
+
instance_eval("def #{d.name}; return devices[:#{d.name}]; end")
|
|
295
|
+
@devices[d.name.intern] = d
|
|
296
|
+
}
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'active_support/inflector'
|
|
2
|
+
|
|
3
|
+
module Artoo
|
|
4
|
+
module Utility
|
|
5
|
+
def constantize(camel_cased_word)
|
|
6
|
+
ActiveSupport::Inflector.constantize(camel_cased_word)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def classify(underscored)
|
|
10
|
+
ActiveSupport::Inflector.camelize(underscored.to_s.sub(/.*\./, ''))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def random_string
|
|
14
|
+
(0...8).map{65.+(rand(26)).chr}.join
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def current_instance
|
|
18
|
+
Celluloid::Actor.current
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def current_class
|
|
22
|
+
Celluloid::Actor.current.class
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# just a bit of syntactic sugar, actually does nothing
|
|
28
|
+
# Example:
|
|
29
|
+
# 20.seconds => 20
|
|
30
|
+
# 1.second => 1
|
|
31
|
+
class Integer < Numeric
|
|
32
|
+
def seconds
|
|
33
|
+
return self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def second
|
|
37
|
+
return self
|
|
38
|
+
end
|
|
39
|
+
end
|