fabriq 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.
@@ -0,0 +1,26 @@
1
+ module Fabriq
2
+ module Logging
3
+
4
+ def config
5
+ Fabriq::Config
6
+ end
7
+
8
+ def info(msg)
9
+ send_output :info, msg
10
+ end
11
+
12
+ def error(msg)
13
+ send_output :error, msg
14
+ end
15
+
16
+ def debug(msg)
17
+ send_output :debug, msg
18
+ end
19
+
20
+ def send_output(level, msg)
21
+ return if self.config.runtime_env == "test"
22
+ puts "#{Time.now.to_s} - #{level.upcase} : #{msg}"
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ module Fabriq
2
+ module PluginPort
3
+ extend self
4
+ extend Fabriq::Logging
5
+
6
+ attr_accessor :plugins
7
+
8
+ def plugin_load_paths
9
+ [File.expand_path("~") + "/.fabriq", Dir.pwd].collect do |base_path|
10
+ Dir.glob("#{base_path}/plugins/*")
11
+ end.flatten
12
+ end
13
+
14
+ def require_plugins
15
+ debug "Plugin Load paths: #{plugin_load_paths}"
16
+
17
+ plugin_load_paths.each do |plugin_base_dir|
18
+ next unless File.exist?(plugin_base_dir)
19
+ require_plugin_from_path plugin_base_dir
20
+ end
21
+ end
22
+
23
+ def require_plugin_from_path(plugin_base_dir)
24
+ plugin_name = plugin_base_dir.split("/").last
25
+ base_file_path = File.join(plugin_base_dir, "lib", "#{plugin_name}.rb")
26
+ if File.exist?(base_file_path)
27
+ require base_file_path
28
+ else
29
+ error("Plugin: #{plugin_name} - Base file not found (#{base_file_path}")
30
+ end
31
+ end
32
+
33
+ def register_plugin(klass, &config_block)
34
+ @plugins ||= []
35
+
36
+ plugin = klass.init
37
+
38
+ if block_given? && plugin.respond_to?(:configurator)
39
+ config_block.call(plugin.configurator)
40
+ end
41
+
42
+ invoke_plugin_callback(plugin, :registered)
43
+ @plugins << plugin
44
+ end
45
+
46
+ def initialize_plugins
47
+ @plugins.each do |plugin|
48
+ invoke_plugin_callback(plugin, :initialized)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def invoke_plugin_callback(plugin, name, *args)
55
+ plugin.send(name.to_sym, *args) if plugin.respond_to?(name.to_sym)
56
+ end
57
+
58
+
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ require_relative "skype/message"
2
+ require_relative "skype/room"
3
+
4
+ module Fabriq
5
+ module Skype
6
+ class << self
7
+
8
+ attr_accessor :adapter
9
+
10
+ def adapter
11
+ @adapter || Fabriq::Adapter
12
+ end
13
+
14
+ def rooms
15
+ adapter.rooms
16
+ end
17
+
18
+ def room_by_id(room_id)
19
+ rooms.select { |room| room.id == room_id }.first
20
+ end
21
+
22
+ def send_message(message)
23
+ adapter.enqueue_outgoing_message(message)
24
+ end
25
+
26
+ def listen_for_messages_to_self(&block)
27
+ adapter.subscribe_to_incoming_messages do |message|
28
+ if message.private_session? || message.direct?
29
+ block.call(message)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ module Fabriq
2
+ module Skype
3
+ class Message
4
+
5
+ attr_accessor :config, :room, :body, :from_name
6
+
7
+ def initialize(room, body, from_name = "")
8
+ @room = room
9
+ @body = body
10
+ @from_name = from_name
11
+ end
12
+
13
+ def config
14
+ @config || Fabriq::Config
15
+ end
16
+
17
+ def private_session?
18
+ self.room.private_session?
19
+ end
20
+
21
+ def direct?
22
+ (self.config.skype_name && self.body.downcase.include?("@#{self.config.skype_name.downcase}")) == true
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ module Fabriq
2
+ module Skype
3
+ class Room
4
+
5
+ attr_accessor :adapter, :id, :topic, :members, :raw
6
+
7
+ def initialize(adapter, id, members, raw)
8
+ @adapter = adapter
9
+ @id = id
10
+ @members = members
11
+ @raw = raw
12
+ end
13
+
14
+ def private_session?
15
+ @members.count == 2
16
+ end
17
+
18
+ def send_message(body, opts = {})
19
+ message = build_message_from_string(body, opts)
20
+ @adapter.enqueue_outgoing_message(message)
21
+ end
22
+
23
+ def build_message_from_string(body, opts = {})
24
+ body = "@%s: %s" % [opts[:to], body] if opts[:to] && !private_session?
25
+ Fabriq::Skype::Message.new(self, body)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,83 @@
1
+ module Fabriq
2
+ class SkypeProxy
3
+
4
+ attr_accessor :adapter, :outgoing_messages
5
+
6
+ def initialize(adapter)
7
+ @adapter = adapter
8
+ @incoming_mutex = Mutex.new
9
+ @outgoing_mutex = Mutex.new
10
+ @incoming_message_callbacks = []
11
+ @outgoing_messages = []
12
+ end
13
+
14
+ def on_incoming_message(&callback)
15
+ @incoming_message_callbacks << callback
16
+ end
17
+
18
+ def subscribe_adapter_message_received
19
+ @received_messages = []
20
+ @adapter.message_received do |message|
21
+ @received_messages << message
22
+ end
23
+ end
24
+
25
+ def start
26
+ subscribe_adapter_message_received
27
+ start_queue_worker_threads
28
+ end
29
+
30
+ def start_queue_worker_threads
31
+ run_in_thread { start_incoming_queue_worker }
32
+ run_in_thread { start_outgoing_queue_worker }
33
+ end
34
+
35
+ def start_incoming_queue_worker
36
+ run_in_throttled_loop do
37
+ handle_incoming_messages_synchronized
38
+ end
39
+ end
40
+
41
+ def start_outgoing_queue_worker
42
+ run_in_throttled_loop do
43
+ handle_outgoing_messages_synchronized
44
+ end
45
+ end
46
+
47
+ def handle_incoming_messages_synchronized
48
+ @incoming_mutex.synchronize do
49
+ invoke_incoming_message_subscribers(@received_messages.shift)
50
+ end
51
+ end
52
+
53
+ def handle_outgoing_messages_synchronized
54
+ @outgoing_mutex.synchronize do
55
+ if @outgoing_messages.count > 0
56
+ message = @outgoing_messages.shift
57
+ @adapter.send_message(message)
58
+ end
59
+ end
60
+ end
61
+
62
+ def invoke_incoming_message_subscribers(message)
63
+ @incoming_message_callbacks.each do |callback|
64
+ run_in_thread { callback.call(message) }
65
+ end
66
+ end
67
+
68
+
69
+ private
70
+
71
+ def run_in_throttled_loop(&block)
72
+ while true
73
+ yield
74
+ sleep 0.5
75
+ end
76
+ end
77
+
78
+ def run_in_thread(&block)
79
+ Thread.new(&block)
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development, :test)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'minitest/spec'
13
+ require 'minitest/pride'
14
+ require 'mocha'
15
+
16
+ ENV['FABRIQ_ENV'] = "test"
17
+
18
+ MiniTest::Unit.autorun
@@ -0,0 +1,153 @@
1
+ require_relative "../../helper"
2
+ require_relative "../../../lib/fabriq/logging"
3
+ require_relative "../../../lib/fabriq/config"
4
+ require_relative "../../../lib/fabriq/adapter"
5
+
6
+ require 'ostruct'
7
+
8
+ describe Fabriq::Adapter do
9
+
10
+ before do
11
+ @skype_adapter = mock('Skype Adapter')
12
+ @subject = Fabriq::Adapter
13
+ @subject.adapter = @skype_adapter
14
+ end
15
+
16
+ describe '#load' do
17
+ it "assigns the configured skype-adapter" do
18
+ Fabriq::Config.adapter = skype_adapter_class = Class.new
19
+ @subject.load
20
+ @subject.adapter.must_be_kind_of(skype_adapter_class )
21
+ end
22
+ end
23
+
24
+ describe '#run' do
25
+ before do
26
+ @subject.stubs(:init_skype_proxy)
27
+ @subject.stubs(:find_available_rooms)
28
+ @skype_adapter.stubs(:attach)
29
+ @skype_adapter.stubs(:wait)
30
+ end
31
+
32
+ it "inits the skype proxy" do
33
+ @subject.expects(:init_skype_proxy)
34
+ @subject.run
35
+ end
36
+
37
+ it "attaches the internal adapter" do
38
+ @skype_adapter.expects(:attach)
39
+ @subject.run
40
+ end
41
+
42
+ it "loads all available rooms from skype" do
43
+ room = mock('Room')
44
+ @subject.expects(:find_available_rooms).yields([room])
45
+ @subject.run
46
+ @subject.rooms.must_include(room)
47
+ end
48
+
49
+ it "calls the passed callback after loading rooms" do
50
+ @subject.stubs(:find_available_rooms).yields()
51
+ proc = -> {}
52
+ proc.expects(:call)
53
+ @subject.run(&proc)
54
+ end
55
+
56
+ it "asks the internal adapter to enable wait mode" do
57
+ @skype_adapter.expects(:wait)
58
+ @subject.run
59
+ end
60
+ end
61
+
62
+ describe '#init_skype_proxy' do
63
+ before do
64
+ @proxy_class = mock('ProxyClass')
65
+ @proxy_instance = mock('ProxyInstance')
66
+ @proxy_class.stubs(:new).returns(@proxy_instance)
67
+ @proxy_instance.stubs(:start)
68
+ @subject.skype_proxy_class = @proxy_class
69
+ end
70
+
71
+ it "creates and assigns a new proxy object" do
72
+ @subject.init_skype_proxy
73
+ @subject.proxy.must_equal(@proxy_instance)
74
+ end
75
+
76
+ it "passes itself as adapter to the proxy instance" do
77
+ @proxy_class.expects(:new).with(@subject).returns(@proxy_instance)
78
+ @subject.init_skype_proxy
79
+ end
80
+
81
+ it "calls #start on the proxy instance" do
82
+ @proxy_instance.expects(:start)
83
+ @subject.init_skype_proxy
84
+ end
85
+ end
86
+
87
+ describe '#find_skype_room_by_id' do
88
+ it "returns the matching room by id" do
89
+ room = mock('Room', :id => "ab99")
90
+ @subject.rooms = [room]
91
+ @subject.find_skype_room_by_id("ab99").must_equal(room)
92
+ end
93
+
94
+ it "returns nil on no match" do
95
+ @subject.rooms = []
96
+ @subject.find_skype_room_by_id("ab99").must_be_nil
97
+ end
98
+ end
99
+
100
+ describe '#enqueue_outgoing_message' do
101
+ it "attaches the passed message to the proxy's outgoing message collection" do
102
+ message = mock('Message')
103
+ @subject.proxy = OpenStruct.new(outgoing_messages: [])
104
+ @subject.proxy.outgoing_messages.expects(:<<).with(message)
105
+ @subject.enqueue_outgoing_message(message)
106
+ end
107
+ end
108
+
109
+ describe '#subscribe_to_incoming_messages' do
110
+ it "adds the passed callback to the proxy's incoming-message-callbacks collection" do
111
+ proc = -> {}
112
+ @subject.proxy = mock('Proxy')
113
+ @subject.proxy.expects(:on_incoming_message).with() { |callback| callback.must_equal(&proc) }
114
+ @subject.subscribe_to_incoming_messages(&proc)
115
+ end
116
+ end
117
+
118
+ describe '#message_received' do
119
+ before do
120
+ @raw_message = { room_id: "abx12" }
121
+ @skype_adapter.stubs(:message_received).yields(@raw_message)
122
+ @subject.stubs(:build_skype_message)
123
+ @subject.stubs(:find_skype_room_by_id)
124
+ end
125
+
126
+ it "hooks into the adapters #message_received event" do
127
+ @skype_adapter.expects(:message_received)
128
+ @subject.message_received
129
+ end
130
+
131
+ it "finds the Skype::Room for a received message" do
132
+ @subject.expects(:find_skype_room_by_id).with("abx12")
133
+ @subject.message_received
134
+ end
135
+
136
+ it "builds a Skype::Message and yields it" do
137
+ proc = -> {}
138
+ skype_message = mock('Message')
139
+ @subject.stubs(:build_skype_message).returns(skype_message)
140
+ proc.expects(:call).with(skype_message)
141
+ @subject.message_received(&proc)
142
+ end
143
+ end
144
+
145
+ describe '#send_message' do
146
+ it "invokes #send_message on the skype adapter" do
147
+ message = OpenStruct.new(room: OpenStruct.new( raw: "raw_room" ), body: "text")
148
+ @skype_adapter.expects(:send_message).with("raw_room", "text")
149
+ @subject.send_message(message)
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,43 @@
1
+ require_relative "../../helper"
2
+ require_relative "../../../lib/fabriq/cli"
3
+
4
+ require 'ostruct'
5
+
6
+ describe Fabriq::CLI do
7
+
8
+ before do
9
+ @cli = Fabriq::CLI
10
+ @cli.stubs(:exit)
11
+ @cli.skype = @skype = mock('Skype')
12
+ end
13
+
14
+ describe '#run' do
15
+ it "lists available rooms if 'rooms' is passed as first argument" do
16
+ @cli.expects(:list_available_rooms)
17
+ @cli.run(['rooms'])
18
+ end
19
+
20
+ it "exists the process with success(0)" do
21
+ @cli.expects(:exit).with(0)
22
+ @cli.run([])
23
+ end
24
+ end
25
+
26
+ describe '#list_available_rooms' do
27
+ before do
28
+ @cli.stubs(:cli_out)
29
+ end
30
+
31
+ it "collects all Skype Rooms" do
32
+ @skype.expects(:rooms).returns([])
33
+ @cli.list_available_rooms
34
+ end
35
+
36
+ it "prints information about each collected room" do
37
+ room = OpenStruct.new({ topic: "Test", id: 99 })
38
+ @skype.stubs(:rooms).returns([room])
39
+ @cli.expects(:cli_out).with() { |out| out =~ /99(.*)Test/ }
40
+ @cli.list_available_rooms
41
+ end
42
+ end
43
+ end