mohiam-babylon 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +111 -0
  3. data/Rakefile +145 -0
  4. data/bin/babylon +6 -0
  5. data/lib/babylon.rb +119 -0
  6. data/lib/babylon/base/controller.rb +116 -0
  7. data/lib/babylon/base/stanza.rb +23 -0
  8. data/lib/babylon/base/view.rb +49 -0
  9. data/lib/babylon/client_connection.rb +210 -0
  10. data/lib/babylon/component_connection.rb +87 -0
  11. data/lib/babylon/generator.rb +139 -0
  12. data/lib/babylon/router.rb +103 -0
  13. data/lib/babylon/router/dsl.rb +61 -0
  14. data/lib/babylon/runner.rb +148 -0
  15. data/lib/babylon/xmpp_connection.rb +172 -0
  16. data/lib/babylon/xmpp_parser.rb +111 -0
  17. data/lib/babylon/xpath_helper.rb +13 -0
  18. data/spec/bin/babylon_spec.rb +0 -0
  19. data/spec/em_mock.rb +42 -0
  20. data/spec/lib/babylon/base/controller_spec.rb +205 -0
  21. data/spec/lib/babylon/base/stanza_spec.rb +15 -0
  22. data/spec/lib/babylon/base/view_spec.rb +86 -0
  23. data/spec/lib/babylon/client_connection_spec.rb +304 -0
  24. data/spec/lib/babylon/component_connection_spec.rb +135 -0
  25. data/spec/lib/babylon/generator_spec.rb +10 -0
  26. data/spec/lib/babylon/router/dsl_spec.rb +72 -0
  27. data/spec/lib/babylon/router_spec.rb +189 -0
  28. data/spec/lib/babylon/runner_spec.rb +213 -0
  29. data/spec/lib/babylon/xmpp_connection_spec.rb +197 -0
  30. data/spec/lib/babylon/xmpp_parser_spec.rb +275 -0
  31. data/spec/lib/babylon/xpath_helper_spec.rb +25 -0
  32. data/spec/spec_helper.rb +34 -0
  33. data/templates/babylon/app/controllers/controller.rb +7 -0
  34. data/templates/babylon/app/stanzas/stanza.rb +6 -0
  35. data/templates/babylon/app/views/view.rb +6 -0
  36. data/templates/babylon/config/boot.rb +16 -0
  37. data/templates/babylon/config/config.yaml +24 -0
  38. data/templates/babylon/config/dependencies.rb +1 -0
  39. data/templates/babylon/config/routes.rb +22 -0
  40. data/templates/babylon/log/development.log +0 -0
  41. data/templates/babylon/log/production.log +0 -0
  42. data/templates/babylon/log/test.log +52 -0
  43. data/templates/babylon/script/component +46 -0
  44. data/templates/babylon/tmp/pids/README +2 -0
  45. data/test/babylon_test.rb +7 -0
  46. data/test/test_helper.rb +10 -0
  47. 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