radamanthus-skates 0.3.5
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/LICENSE +20 -0
- data/README.rdoc +113 -0
- data/Rakefile +142 -0
- data/bin/skates +8 -0
- data/lib/skates.rb +154 -0
- data/lib/skates/base/controller.rb +116 -0
- data/lib/skates/base/stanza.rb +44 -0
- data/lib/skates/base/view.rb +59 -0
- data/lib/skates/client_connection.rb +234 -0
- data/lib/skates/component_connection.rb +114 -0
- data/lib/skates/ext/array.rb +21 -0
- data/lib/skates/generator.rb +142 -0
- data/lib/skates/router.rb +123 -0
- data/lib/skates/router/dsl.rb +48 -0
- data/lib/skates/runner.rb +164 -0
- data/lib/skates/xmpp_connection.rb +216 -0
- data/lib/skates/xmpp_parser.rb +112 -0
- data/spec/bin/skates_spec.rb +0 -0
- data/spec/em_mock.rb +42 -0
- data/spec/lib/skates/base/controller_spec.rb +205 -0
- data/spec/lib/skates/base/stanza_spec.rb +120 -0
- data/spec/lib/skates/base/view_spec.rb +105 -0
- data/spec/lib/skates/client_connection_spec.rb +309 -0
- data/spec/lib/skates/component_connection_spec.rb +144 -0
- data/spec/lib/skates/generator_spec.rb +10 -0
- data/spec/lib/skates/router/dsl_spec.rb +46 -0
- data/spec/lib/skates/router_spec.rb +252 -0
- data/spec/lib/skates/runner_spec.rb +233 -0
- data/spec/lib/skates/xmpp_connection_spec.rb +222 -0
- data/spec/lib/skates/xmpp_parser_spec.rb +283 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +37 -0
- data/test/skates_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +125 -0
@@ -0,0 +1,216 @@
|
|
1
|
+
module Skates
|
2
|
+
|
3
|
+
##
|
4
|
+
# Connection Exception
|
5
|
+
class NotConnected < StandardError; end
|
6
|
+
|
7
|
+
##
|
8
|
+
# xml-not-well-formed Exception
|
9
|
+
class XmlNotWellFormed < StandardError; end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Error when there is no connection to the host and port.
|
13
|
+
class NoConnection < StandardError; end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Authentication Error (wrong password/jid combination). Used for Clients and Components
|
17
|
+
class AuthenticationError < StandardError; end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Raised when the application tries to send a stanza that might be rejected by the server because it's too long.
|
21
|
+
class StanzaTooBig < StandardError; end
|
22
|
+
|
23
|
+
##
|
24
|
+
# This class is in charge of handling the network connection to the XMPP server.
|
25
|
+
class XmppConnection < EventMachine::Connection
|
26
|
+
|
27
|
+
attr_accessor :jid, :host, :port
|
28
|
+
|
29
|
+
@@max_stanza_size = 65535
|
30
|
+
|
31
|
+
##
|
32
|
+
# This will the host asynscrhonously and calls the block for each IP:Port pair.
|
33
|
+
# if the block returns true, no other record will be tried. If it returns false, the block will be called with the next pair.
|
34
|
+
def self.resolve(host, &block)
|
35
|
+
block.call(false)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Maximum Stanza size. Default is 65535
|
40
|
+
def self.max_stanza_size
|
41
|
+
@@max_stanza_size
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Setter for Maximum Stanza size.
|
46
|
+
def self.max_stanza_size=(_size)
|
47
|
+
@@max_stanza_size = _size
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Connects the XmppConnection to the right host with the right port.
|
52
|
+
# It passes itself (as handler) and the configuration
|
53
|
+
# This can very well be overwritten by subclasses.
|
54
|
+
def self.connect(params, handler)
|
55
|
+
if params["host"] =~ /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/
|
56
|
+
params["port"] = params["port"] ? params["port"].to_i : 5222
|
57
|
+
_connect(params, handler)
|
58
|
+
else
|
59
|
+
resolve(params["host"]) do |host_info|
|
60
|
+
if host_info
|
61
|
+
begin
|
62
|
+
_connect(params.merge(host_info), handler)
|
63
|
+
true # connected! Yay!
|
64
|
+
rescue NotConnected
|
65
|
+
# It will try the next pair of ip/port
|
66
|
+
false
|
67
|
+
end
|
68
|
+
else
|
69
|
+
Skates.logger.error {
|
70
|
+
"Sorry, we couldn't resolve #{srv_for_host(params["host"])} to any host that accept XMPP connections. Please provide a params[\"host\"]."
|
71
|
+
}
|
72
|
+
EM.stop_event_loop
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Called when the connection is completed.
|
80
|
+
def connection_completed
|
81
|
+
@connected = true
|
82
|
+
Skates.logger.debug {
|
83
|
+
"CONNECTED"
|
84
|
+
} # Very low level Logging
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Called when the connection is terminated and stops the event loop
|
89
|
+
def unbind()
|
90
|
+
@connected = false
|
91
|
+
Skates.logger.debug {
|
92
|
+
"DISCONNECTED"
|
93
|
+
} # Very low level Logging
|
94
|
+
begin
|
95
|
+
@handler.on_disconnected() if @handler and @handler.respond_to?("on_disconnected")
|
96
|
+
rescue
|
97
|
+
Skates.logger.error {
|
98
|
+
"on_disconnected failed : #{$!}\n#{$!.backtrace.join("\n")}"
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Instantiate the Handler (called internally by EventMachine)
|
105
|
+
def initialize(params = {})
|
106
|
+
@connected = false
|
107
|
+
@jid = params["jid"]
|
108
|
+
@password = params["password"]
|
109
|
+
@host = params["host"]
|
110
|
+
@port = params["port"]
|
111
|
+
@handler = params["handler"]
|
112
|
+
@buffer = ""
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Attaches a new parser since the network connection has been established.
|
117
|
+
def post_init
|
118
|
+
@parser = XmppParser.new(method(:receive_stanza))
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Called when a full stanza has been received and returns it to the central router to be sent to the corresponding controller.
|
123
|
+
def receive_stanza(stanza)
|
124
|
+
Skates.logger.debug {
|
125
|
+
"PARSED : #{stanza.to_xml}"
|
126
|
+
}
|
127
|
+
# If not handled by subclass (for authentication)
|
128
|
+
case stanza.name
|
129
|
+
when "stream:error"
|
130
|
+
if !stanza.children.empty? and stanza.children.first.name == "xml-not-well-formed"
|
131
|
+
Skates.logger.error {
|
132
|
+
"DISCONNECTED DUE TO MALFORMED STANZA"
|
133
|
+
}
|
134
|
+
raise XmlNotWellFormed
|
135
|
+
end
|
136
|
+
# In any case, we need to close the connection.
|
137
|
+
close_connection
|
138
|
+
else
|
139
|
+
begin
|
140
|
+
@handler.on_stanza(stanza) if @handler and @handler.respond_to?("on_stanza")
|
141
|
+
rescue
|
142
|
+
Skates.logger.error {
|
143
|
+
"on_stanza failed : #{$!}\n#{$!.backtrace.join("\n")}"
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Sends the Nokogiri::XML data (after converting to string) on the stream. Eventually it displays this data for debugging purposes.
|
151
|
+
def send_xml(xml)
|
152
|
+
begin
|
153
|
+
if xml.is_a? Nokogiri::XML::NodeSet
|
154
|
+
xml.each do |element|
|
155
|
+
send_chunk(element.to_s)
|
156
|
+
end
|
157
|
+
else
|
158
|
+
send_chunk(xml.to_s)
|
159
|
+
end
|
160
|
+
rescue
|
161
|
+
Skates.logger.error {
|
162
|
+
"SENDING FAILED: #{$!}"
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def send_chunk(string = "")
|
170
|
+
raise NotConnected unless @connected
|
171
|
+
return if string == ""
|
172
|
+
raise StanzaTooBig, "Stanza Too Big (#{string.length} vs. #{XmppConnection.max_stanza_size})\n #{string}" if string.length > XmppConnection.max_stanza_size
|
173
|
+
Skates.logger.debug {
|
174
|
+
"SENDING : " + string
|
175
|
+
}
|
176
|
+
send_data UTF8Cleaner.clean(string)
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# receive_data is called when data is received. It is then passed to the parser.
|
181
|
+
def receive_data(data)
|
182
|
+
data = UTF8Cleaner.clean(data)
|
183
|
+
begin
|
184
|
+
Skates.logger.debug {
|
185
|
+
"RECEIVED : #{data}"
|
186
|
+
}
|
187
|
+
@parser.push(data)
|
188
|
+
rescue
|
189
|
+
Skates.logger.error {
|
190
|
+
"#{$!}\n#{$!.backtrace.join("\n")}"
|
191
|
+
}
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.srv_for_host(host)
|
196
|
+
"#{host}"
|
197
|
+
end
|
198
|
+
|
199
|
+
def self._connect(params, handler)
|
200
|
+
Skates.logger.debug {
|
201
|
+
"CONNECTING TO #{params["host"]}:#{params["port"]} with #{handler.inspect} as connection handler" # Very low level Logging
|
202
|
+
}
|
203
|
+
begin
|
204
|
+
EventMachine.connect(params["host"], params["port"], self, params.merge({"handler" => handler}))
|
205
|
+
rescue RuntimeError
|
206
|
+
Skates.logger.error {
|
207
|
+
"CONNECTION ERROR : #{$!.class} => #{$!}" # Very low level Logging
|
208
|
+
}
|
209
|
+
raise NotConnected
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Skates
|
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
|
+
|
48
|
+
add_namespaces_and_attributes_to_current_node(attributes)
|
49
|
+
|
50
|
+
if @elem.name == "stream:stream"
|
51
|
+
# We activate the callback since this element will never end.
|
52
|
+
@callback.call(@elem)
|
53
|
+
@doc = @elem = nil # Let's prepare for the next stanza
|
54
|
+
# And then, we start a new Sax Push Parser
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Clears the characters buffer
|
60
|
+
def clear_characters_buffer
|
61
|
+
if @buffer && @elem
|
62
|
+
@buffer.strip!
|
63
|
+
@elem.add_child(Nokogiri::XML::Text.new(@buffer, @doc)) unless @buffer.empty?
|
64
|
+
@buffer = nil # empty the buffer
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Terminates the current element and calls the callback
|
70
|
+
def end_element(name)
|
71
|
+
clear_characters_buffer
|
72
|
+
if @elem
|
73
|
+
if @elem.parent == @doc
|
74
|
+
# If we're actually finishing the stanza (a stanza is always a document's root)
|
75
|
+
@callback.call(@elem)
|
76
|
+
# We delete the current element and the doc (1 doc per stanza policy)
|
77
|
+
@elem = @doc = nil
|
78
|
+
else
|
79
|
+
@elem = @elem.parent
|
80
|
+
end
|
81
|
+
else
|
82
|
+
# Not sure what to do since it seems we're not processing any element at this time, so how can one end?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Adds namespaces and attributes. Nokogiri passes them as a array of [[ns_name, ns_url], [ns_name, ns_url]..., key, value, key, value]...
|
88
|
+
def add_namespaces_and_attributes_to_current_node(attrs)
|
89
|
+
# Namespaces
|
90
|
+
attrs.select {|k| k.is_a? Array}.each do |pair|
|
91
|
+
set_namespace(pair[0], pair[1])
|
92
|
+
# set_normal_attribute(pair[0], pair[1])
|
93
|
+
end
|
94
|
+
# Attributes
|
95
|
+
attrs.select {|k| k.is_a? String}.in_groups_of(2) do |pair|
|
96
|
+
set_normal_attribute(pair[0], pair[1])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_normal_attribute(key, value)
|
101
|
+
@elem.set_attribute key, Skates.decode_xml(value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_namespace(key, value)
|
105
|
+
if key.include? ':'
|
106
|
+
@elem.add_namespace(key.split(':').last, value)
|
107
|
+
else
|
108
|
+
@elem.add_namespace(nil, value)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
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 Skates::Base::Controller do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
Skates.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 = Skates::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 = Skates::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 = Skates::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
|
+
Skates.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 = Skates::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(Skates::Base::Stanza)
|
120
|
+
@controller = Skates::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 < Skates::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 = Skates::Base::Controller.new()
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should evaluate the view" do
|
153
|
+
view = mock(Skates::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 = Skates::Base::Controller.new()
|
164
|
+
file_name = "myfile"
|
165
|
+
@controller.__send__(:view_path, file_name).should == File.join("app/views", "#{"Skates::Base::Controller".gsub("Controller","").downcase}", file_name)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe ".default_template_name" do
|
170
|
+
before(:each) do
|
171
|
+
@controller = Skates::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 = Skates::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 = Skates::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
|
+
Skates::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
|