mohiam-babylon 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +111 -0
- data/Rakefile +145 -0
- data/bin/babylon +6 -0
- data/lib/babylon.rb +119 -0
- data/lib/babylon/base/controller.rb +116 -0
- data/lib/babylon/base/stanza.rb +23 -0
- data/lib/babylon/base/view.rb +49 -0
- data/lib/babylon/client_connection.rb +210 -0
- data/lib/babylon/component_connection.rb +87 -0
- data/lib/babylon/generator.rb +139 -0
- data/lib/babylon/router.rb +103 -0
- data/lib/babylon/router/dsl.rb +61 -0
- data/lib/babylon/runner.rb +148 -0
- data/lib/babylon/xmpp_connection.rb +172 -0
- data/lib/babylon/xmpp_parser.rb +111 -0
- data/lib/babylon/xpath_helper.rb +13 -0
- data/spec/bin/babylon_spec.rb +0 -0
- data/spec/em_mock.rb +42 -0
- data/spec/lib/babylon/base/controller_spec.rb +205 -0
- data/spec/lib/babylon/base/stanza_spec.rb +15 -0
- data/spec/lib/babylon/base/view_spec.rb +86 -0
- data/spec/lib/babylon/client_connection_spec.rb +304 -0
- data/spec/lib/babylon/component_connection_spec.rb +135 -0
- data/spec/lib/babylon/generator_spec.rb +10 -0
- data/spec/lib/babylon/router/dsl_spec.rb +72 -0
- data/spec/lib/babylon/router_spec.rb +189 -0
- data/spec/lib/babylon/runner_spec.rb +213 -0
- data/spec/lib/babylon/xmpp_connection_spec.rb +197 -0
- data/spec/lib/babylon/xmpp_parser_spec.rb +275 -0
- data/spec/lib/babylon/xpath_helper_spec.rb +25 -0
- data/spec/spec_helper.rb +34 -0
- data/templates/babylon/app/controllers/controller.rb +7 -0
- data/templates/babylon/app/stanzas/stanza.rb +6 -0
- data/templates/babylon/app/views/view.rb +6 -0
- data/templates/babylon/config/boot.rb +16 -0
- data/templates/babylon/config/config.yaml +24 -0
- data/templates/babylon/config/dependencies.rb +1 -0
- data/templates/babylon/config/routes.rb +22 -0
- data/templates/babylon/log/development.log +0 -0
- data/templates/babylon/log/production.log +0 -0
- data/templates/babylon/log/test.log +52 -0
- data/templates/babylon/script/component +46 -0
- data/templates/babylon/tmp/pids/README +2 -0
- data/test/babylon_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +179 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
module Babylon
|
2
|
+
|
3
|
+
##
|
4
|
+
# This is the XML SAX Parser that accepts "pushed" content
|
5
|
+
class XmppParser < Nokogiri::XML::SAX::Document
|
6
|
+
|
7
|
+
attr_accessor :elem, :doc, :parser
|
8
|
+
|
9
|
+
##
|
10
|
+
# Initialize the parser and adds the callback that will be called upon stanza completion
|
11
|
+
def initialize(callback)
|
12
|
+
@callback = callback
|
13
|
+
@buffer = ""
|
14
|
+
super()
|
15
|
+
reset
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Resets the Pushed SAX Parser.
|
20
|
+
def reset
|
21
|
+
@parser = Nokogiri::XML::SAX::PushParser.new(self, "UTF-8")
|
22
|
+
@elem = @doc = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Pushes the received data to the parser. The parser will then callback the document's methods (start_tag, end_tag... etc)
|
27
|
+
def push(data)
|
28
|
+
@parser << data
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Adds characters to the current element (being parsed)
|
33
|
+
def characters(string)
|
34
|
+
@buffer ||= ""
|
35
|
+
@buffer += string
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Instantiate a new current Element, adds the corresponding attributes and namespaces.
|
40
|
+
# The new element is eventually added to a parent element (if present).
|
41
|
+
# If no element is being parsed, then, we create a new document, to which we add this new element as root. (we create one document per stanza to avoid memory problems)
|
42
|
+
def start_element(qname, attributes = [])
|
43
|
+
clear_characters_buffer
|
44
|
+
@doc ||= Nokogiri::XML::Document.new
|
45
|
+
@elem ||= @doc # If we have no current element, then, we take the doc
|
46
|
+
@elem = @elem.add_child(Nokogiri::XML::Element.new(qname, @doc))
|
47
|
+
add_namespaces_and_attributes_to_current_node(attributes)
|
48
|
+
|
49
|
+
if @elem.name == "stream:stream"
|
50
|
+
# We activate the callback since this element will never end.
|
51
|
+
@callback.call(@elem)
|
52
|
+
@doc = @elem = nil # Let's prepare for the next stanza
|
53
|
+
# And then, we start a new Sax Push Parser
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Clears the characters buffer
|
59
|
+
def clear_characters_buffer
|
60
|
+
if @buffer && @elem
|
61
|
+
@buffer.strip!
|
62
|
+
@elem.add_child(Nokogiri::XML::Text.new(Babylon.decode_xml(@buffer), @doc)) unless @buffer.empty?
|
63
|
+
@buffer = nil # empty the buffer
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Terminates the current element and calls the callback
|
69
|
+
def end_element(name)
|
70
|
+
clear_characters_buffer
|
71
|
+
if @elem
|
72
|
+
if @elem.parent == @doc
|
73
|
+
# If we're actually finishing the stanza (a stanza is always a document's root)
|
74
|
+
@callback.call(@elem)
|
75
|
+
# We delete the current element and the doc (1 doc per stanza policy)
|
76
|
+
@elem = @doc = nil
|
77
|
+
else
|
78
|
+
@elem = @elem.parent
|
79
|
+
end
|
80
|
+
else
|
81
|
+
# Not sure what to do since it seems we're not processing any element at this time, so how can one end?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
##
|
88
|
+
# Adds namespaces and attributes. Nokogiri passes them as a array of [name, value, name, value]...
|
89
|
+
def add_namespaces_and_attributes_to_current_node(attrs)
|
90
|
+
|
91
|
+
# strip out arrays from the incoming attributes
|
92
|
+
# these tend to be namespaces. They break the code below
|
93
|
+
attrs = attrs.select{ |attr| attr.kind_of? String }
|
94
|
+
|
95
|
+
(attrs.size / 2).times do |i|
|
96
|
+
name, value = attrs[2 * i], attrs[2 * i + 1]
|
97
|
+
|
98
|
+
# TODO : FIX namespaces :they give a lot of problems with Nokogiri
|
99
|
+
# if name == "xmlns"
|
100
|
+
# @elem.add_namespace(nil, value)
|
101
|
+
# elsif name =~ /\Axmlns:/
|
102
|
+
# @elem.add_namespace(name.gsub("xmlns:", ""), value)
|
103
|
+
# else
|
104
|
+
|
105
|
+
#
|
106
|
+
@elem.set_attribute name, Babylon.decode_xml(value)
|
107
|
+
# end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Babylon
|
2
|
+
|
3
|
+
# Custom XPath functions for stanza-routing.
|
4
|
+
class XpathHelper
|
5
|
+
|
6
|
+
# Match nodes of the given name with the given namespace URI.
|
7
|
+
def namespace(set, name, nsuri)
|
8
|
+
set.find_all do |n|
|
9
|
+
n.name == name && n.namespaces.values.include?(nsuri)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
File without changes
|
data/spec/em_mock.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
##
|
2
|
+
# Mock for EventMachine
|
3
|
+
module EventMachine
|
4
|
+
|
5
|
+
def self.mock?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Mock for the Connection Class
|
11
|
+
class Connection
|
12
|
+
def self.new(*args)
|
13
|
+
allocate.instance_eval do
|
14
|
+
# Call a superclass's #initialize if it has one
|
15
|
+
initialize(*args)
|
16
|
+
# Store signature and run #post_init
|
17
|
+
post_init
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Stub for run
|
25
|
+
def self.run(proc)
|
26
|
+
proc.call
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Stub for epoll
|
31
|
+
def self.epoll; end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Stub! to stop the event loop.
|
35
|
+
def self.stop_event_loop; end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Stub for connect (should return a connection object)
|
39
|
+
def self.connect(host, port, handler, params)
|
40
|
+
handler.new(params)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Babylon::Base::Controller do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
Babylon.views.stub!(:[]).and_return("") # Stubbing read for view
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ".initialize" do
|
10
|
+
before(:each) do
|
11
|
+
@params = {:a => "a", :b => 1, :c => {:key => "value"}, :stanza => "<hello>world</hello>"}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a stanza instance" do
|
15
|
+
stanza = mock(Object)
|
16
|
+
c = Babylon::Base::Controller.new(stanza)
|
17
|
+
|
18
|
+
c.instance_variables.should be_include "@stanza"
|
19
|
+
c.instance_variable_get("@stanza").should == stanza
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not be rendered yet" do
|
23
|
+
c = Babylon::Base::Controller.new(@params)
|
24
|
+
c.rendered.should_not be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".perform" do
|
29
|
+
before(:each) do
|
30
|
+
@action = :subscribe
|
31
|
+
params = {:stanza => "<hello>world</hello>"}
|
32
|
+
@controller = Babylon::Base::Controller.new(params)
|
33
|
+
@controller.class.send(:define_method, @action) do # Defining the action method
|
34
|
+
# Do something
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should setup the action to the param" do
|
39
|
+
@controller.perform(@action) do
|
40
|
+
# Do something
|
41
|
+
end
|
42
|
+
@controller.instance_variable_get("@action_name").should == @action
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should call the action" do
|
46
|
+
@controller.should_receive(:send).with(@action).and_return()
|
47
|
+
@controller.perform(@action) do
|
48
|
+
# Do something
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should write an error to the log in case of failure of the action" do
|
53
|
+
@controller.stub!(:send).with(@action).and_raise(StandardError)
|
54
|
+
Babylon.logger.should_receive(:error)
|
55
|
+
@controller.perform(@action) do
|
56
|
+
# Do something
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should call render" do
|
61
|
+
@controller.should_receive(:render)
|
62
|
+
@controller.perform(@action) do
|
63
|
+
# Do something
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe ".render" do
|
69
|
+
before(:each) do
|
70
|
+
@controller = Babylon::Base::Controller.new({})
|
71
|
+
@controller.action_name = :subscribe
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should assign a value to view" do
|
75
|
+
@controller.render
|
76
|
+
@controller.instance_variable_get("@view").should_not be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "with :nothing option" do
|
80
|
+
it "should not render any file" do
|
81
|
+
@controller.should_not_receive(:render_for_file)
|
82
|
+
@controller.render :nothing => true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "with no option" do
|
87
|
+
it "should call render with default_file_name if no option is provided" do
|
88
|
+
@controller.should_receive(:default_template_name)
|
89
|
+
@controller.render
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "with an :action option" do
|
94
|
+
it "should call render with the file name corresponding to the action given as option" do
|
95
|
+
action = :unsubscribe
|
96
|
+
@controller.should_receive(:default_template_name).with("#{action}")
|
97
|
+
@controller.render(:action => action)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "with a file option" do
|
102
|
+
it "should call render_for_file with the correct path if an option file is provided" do
|
103
|
+
file = "myfile"
|
104
|
+
@controller.should_receive(:render_for_file)
|
105
|
+
@controller.render(:file => file)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not render twice when called twice" do
|
110
|
+
@controller.render
|
111
|
+
@controller.should_not_receive(:render_for_file)
|
112
|
+
@controller.render
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe ".assigns" do
|
117
|
+
|
118
|
+
before(:each) do
|
119
|
+
@stanza = mock(Babylon::Base::Stanza)
|
120
|
+
@controller = Babylon::Base::Controller.new(@stanza)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should be a hash" do
|
124
|
+
@controller.assigns.should be_an_instance_of(Hash)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should only contain the @stanza if the action hasn't been called yet" do
|
128
|
+
@controller.assigns.should_not be_empty
|
129
|
+
@controller.assigns["stanza"].should == @stanza
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should return an hash containing all instance variables defined in the action" do
|
133
|
+
vars = {"a" => 1, "b" => "b", "c" => { "d" => 4}}
|
134
|
+
class MyController < Babylon::Base::Controller
|
135
|
+
def do_something
|
136
|
+
@a = 1
|
137
|
+
@b = "b"
|
138
|
+
@c = { "d" => 4 }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
@controller = MyController.new(@stanza)
|
142
|
+
@controller.do_something
|
143
|
+
@controller.assigns.should == vars.merge("stanza" => @stanza)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe ".evaluate" do
|
148
|
+
before(:each) do
|
149
|
+
@controller = Babylon::Base::Controller.new()
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should evaluate the view" do
|
153
|
+
view = mock(Babylon::Base::View)
|
154
|
+
response = "hello"
|
155
|
+
@controller.instance_variable_set("@view", view)
|
156
|
+
view.should_receive(:evaluate).and_return(response)
|
157
|
+
@controller.evaluate.should == response
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe ".view_path" do
|
162
|
+
it "should return complete file path to the file given in param" do
|
163
|
+
@controller = Babylon::Base::Controller.new()
|
164
|
+
file_name = "myfile"
|
165
|
+
@controller.__send__(:view_path, file_name).should == File.join("app/views", "#{"Babylon::Base::Controller".gsub("Controller","").downcase}", file_name)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe ".default_template_name" do
|
170
|
+
before(:each) do
|
171
|
+
@controller = Babylon::Base::Controller.new()
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should return the view file name if a file is given in param" do
|
175
|
+
@controller.__send__(:default_template_name, "myaction").should == "myaction.xml.builder"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should return the view file name based on the action_name if no file has been given" do
|
179
|
+
@controller.action_name = "a_great_action"
|
180
|
+
@controller.__send__(:default_template_name).should == "a_great_action.xml.builder"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe ".render_for_file" do
|
185
|
+
|
186
|
+
before(:each) do
|
187
|
+
@controller = Babylon::Base::Controller.new()
|
188
|
+
@block = Proc.new {
|
189
|
+
# Do something
|
190
|
+
}
|
191
|
+
@controller.class.send(:define_method, "action") do # Defining the action method
|
192
|
+
# Do something
|
193
|
+
end
|
194
|
+
@controller.perform(:action, &@block)
|
195
|
+
@view = Babylon::Base::View.new("path_to_a_file", {})
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should instantiate a new view, with the file provided and the hashed_variables" do
|
199
|
+
Babylon::Base::View.should_receive(:new).with("path_to_a_file",an_instance_of(Hash)).and_return(@view)
|
200
|
+
@controller.__send__(:render_for_file, "path_to_a_file")
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Babylon::Base::Stanza do
|
4
|
+
|
5
|
+
describe "initialize" do
|
6
|
+
before(:each) do
|
7
|
+
@stanza_string = "<presence />"
|
8
|
+
@stanza = Babylon::Base::Stanza.new(@stanza_string)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should call parse with the string passed to the builder"
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Babylon::Base::View do
|
4
|
+
describe ".initialize" do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@view = Babylon::Base::View.new("/a/path/to/a/view/file", {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should assign @view_template to path" do
|
11
|
+
@view.view_template == "/a/path/to/a/view/file"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should assign any variable passed in hash" do
|
15
|
+
{:a => "a", :b => 123, :c => {:d => "d", :e => "123"}}.each do |key, value|
|
16
|
+
@view.instance_variable_get("@#{key}").should == value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".evaluate" do
|
22
|
+
before(:each) do
|
23
|
+
@view_template = "/a/path/to/a/view/file"
|
24
|
+
@view = Babylon::Base::View.new(@view_template, {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
25
|
+
@xml_string = <<-eoxml
|
26
|
+
xml.message(:to => "you", :from => "me", :type => :chat) do
|
27
|
+
xml.body("salut")
|
28
|
+
end
|
29
|
+
eoxml
|
30
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should read the template file" do
|
34
|
+
Babylon.views.should_receive(:[]).twice.with(@view_template).and_return(@xml_string)
|
35
|
+
@view.evaluate
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise an error if the view file couldn't be found" do
|
39
|
+
Babylon.views.stub!(:[]).with(@view_template).and_raise(nil)
|
40
|
+
lambda {
|
41
|
+
@view.evaluate
|
42
|
+
}.should raise_error(Babylon::Base::ViewFileNotFound)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return a Nokogiri NodeSet" do
|
46
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
47
|
+
@view.evaluate.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should call eval on the view file" do
|
51
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
52
|
+
@view.should_receive(:eval).with(@xml_string, an_instance_of(Binding), @view_template, 1)
|
53
|
+
@view.evaluate
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to access context's variables" do
|
57
|
+
@view = Babylon::Base::View.new("/a/path/to/a/view/file", {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
58
|
+
@view.instance_variable_get("@a").should == "a"
|
59
|
+
@view.instance_variable_get("@b").should == 123
|
60
|
+
@view.instance_variable_get("@c").should == {:e=>"123", :d=>"d"}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "render" do
|
65
|
+
before(:each) do
|
66
|
+
@view_template = "/a/path/to/a/view/file"
|
67
|
+
@view = Babylon::Base::View.new(@view_template, {:a => "a", :b => 123, :c => {:d => "d", :e => "123"}})
|
68
|
+
@xml_string = <<-eoxml
|
69
|
+
xml.message(:to => "you", :from => "me", :type => :chat) do |message|
|
70
|
+
message.body("salut")
|
71
|
+
render(message, {:partial => "partial"})
|
72
|
+
end
|
73
|
+
eoxml
|
74
|
+
@partial_string = <<-eoxml
|
75
|
+
xml.title("hello word")
|
76
|
+
eoxml
|
77
|
+
Babylon.views.stub!(:[]).with(@view_template).and_return(@xml_string)
|
78
|
+
Babylon.views.stub!(:[]).with("/a/path/to/a/view/partial.xml.builder").and_return(@partial_string)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should render the partial in the right context" do
|
82
|
+
@view.evaluate.xpath("//message/title").text.should == "hello word"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|