radamanthus-skates 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|