hotwire 0.0.0 → 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.
- data/README.markdown +82 -0
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/hotwire.gemspec +30 -23
- data/lib/hotwire.rb +13 -7
- data/lib/hotwire/base.rb +44 -0
- data/lib/hotwire/request.rb +60 -0
- data/lib/hotwire/response.rb +18 -0
- data/lib/hotwire/response/base.rb +54 -0
- data/lib/hotwire/response/csv.rb +17 -0
- data/lib/hotwire/response/html.rb +11 -0
- data/lib/hotwire/response/invalid.rb +16 -0
- data/lib/hotwire/response/json.rb +96 -0
- data/test/response/test_base.rb +46 -0
- data/test/response/test_csv.rb +27 -0
- data/test/response/test_html.rb +26 -0
- data/test/response/test_invalid.rb +24 -0
- data/test/response/test_json.rb +30 -0
- data/test/test_active_record_mixins.rb +61 -65
- data/test/test_helper.rb +12 -0
- data/test/test_request.rb +56 -0
- data/test/test_response.rb +42 -0
- metadata +31 -24
- data/README.makrdown +0 -46
- data/lib/hotwire/active_record_mixins.rb +0 -95
- data/lib/hotwire/column_headers.rb +0 -54
- data/lib/hotwire/core_extensions.rb +0 -11
- data/lib/hotwire/row.rb +0 -46
- data/lib/hotwire/table.rb +0 -27
- data/test/active_record_test_helper.rb +0 -14
- data/test/test_column_headers.rb +0 -20
- data/test/test_core_extensions.rb +0 -26
- data/test/test_row.rb +0 -17
- data/test/test_table.rb +0 -40
@@ -0,0 +1,96 @@
|
|
1
|
+
module Hotwire
|
2
|
+
module Response
|
3
|
+
# Specialization responsible for producing responses in JSON format.
|
4
|
+
class Json < Hotwire::Response::Base
|
5
|
+
|
6
|
+
def initialize(request)
|
7
|
+
super(request)
|
8
|
+
@responseHandler = "google.visualization.Query.setResponse"
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns the datasource in JSON format. It supports the +responseHandler+
|
12
|
+
# parameter. All the errors are returned with the +invalid_request+ key.
|
13
|
+
# Warnings are unsupported (yet).
|
14
|
+
def body
|
15
|
+
rsp = {}
|
16
|
+
rsp[:version] = @version
|
17
|
+
rsp[:reqId] = @request[:reqId] if @request[:reqId]
|
18
|
+
if valid?
|
19
|
+
rsp[:status] = "ok"
|
20
|
+
rsp[:table] = datatable unless data.nil?
|
21
|
+
else
|
22
|
+
rsp[:status] = "error"
|
23
|
+
rsp[:errors] = @errors
|
24
|
+
end
|
25
|
+
"#{@request[:responseHandler] || @responseHandler}(#{rsp.to_json})"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Renders the part of the JSON response that contains the dataset.
|
29
|
+
def datatable
|
30
|
+
dt = {}
|
31
|
+
dt[:cols] = columns
|
32
|
+
dt[:rows] = []
|
33
|
+
data.each do |datarow|
|
34
|
+
row = []
|
35
|
+
datarow.each_with_index do |datacell, colnum|
|
36
|
+
row << { :v => convert_cell(datacell, columns[colnum][:type]) }
|
37
|
+
end
|
38
|
+
|
39
|
+
dt[:rows] << { :c => row }
|
40
|
+
end
|
41
|
+
return dt
|
42
|
+
end
|
43
|
+
protected :datatable
|
44
|
+
|
45
|
+
# Converts a value in the dataset into a format suitable for the
|
46
|
+
# column it belongs to.
|
47
|
+
#
|
48
|
+
# Datasets are expected to play nice, and try to adhere to the columns they
|
49
|
+
# intend to export as much as possible. This method doesn't do anything more
|
50
|
+
# than the very minimum to ensure a formally valid wire export.
|
51
|
+
def convert_cell(value, coltype)
|
52
|
+
case coltype
|
53
|
+
when "boolean"
|
54
|
+
value ? 'true' : 'false'
|
55
|
+
when "number"
|
56
|
+
value
|
57
|
+
when "string"
|
58
|
+
value
|
59
|
+
when "date"
|
60
|
+
Hotwire::Response::Json::Date.new(value)
|
61
|
+
when "datetime"
|
62
|
+
Hotwire::Response::Json::Datetime.new(value)
|
63
|
+
when "timeofday"
|
64
|
+
[ value.hour, value.min, value.sec, value.usec / 1000 ]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
protected :convert_cell
|
68
|
+
|
69
|
+
# Utility class to produce a JSON rendering of dates compatible with
|
70
|
+
# what the Wire APIs expect ( a Javascript date object )
|
71
|
+
class Date
|
72
|
+
def initialize(date)
|
73
|
+
@date = date
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_json(options=nil)
|
77
|
+
"new Date(#{@date.year}, #{@date.month-1}, #{@date.day})"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Utility class to produce a JSON rendering of datetimes compatible with
|
82
|
+
# what the Wire APIs expect ( a Javascript date object )
|
83
|
+
class DateTime
|
84
|
+
def initialize(datetime)
|
85
|
+
@datetime = datetime
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_json(options=nil)
|
89
|
+
"new Date(#{@date.year}, #{@date.month-1}, #{@date.day}, #{@date.hour}, #{@date.min}, #{@date.sec})"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestResponseBase < Test::Unit::TestCase
|
4
|
+
context "the Hotwire::Response::Base instance" do
|
5
|
+
|
6
|
+
context "created from a valid request" do
|
7
|
+
setup { @response = Hotwire::Response::Base.new(valid_request) }
|
8
|
+
|
9
|
+
context "add_col" do
|
10
|
+
context "with a valid type" do
|
11
|
+
setup { @response.add_column("string", :id => "col_a", :label => "Col A", :invalid_attr => "invalid")}
|
12
|
+
|
13
|
+
should "add to the colums array" do
|
14
|
+
assert_equal({:type => "string", :id => "col_a", :label => "Col A"}, @response.columns.first)
|
15
|
+
end
|
16
|
+
|
17
|
+
should "strip invalid attributes" do
|
18
|
+
assert !@response.columns.first.has_key?(:invalid_attr)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with an invalid type" do
|
23
|
+
should "raise an ArgumetError" do
|
24
|
+
assert_raises ArgumentError do
|
25
|
+
@response.add_col("invalid_type")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
context "set_data" do
|
33
|
+
setup do
|
34
|
+
@data = [['a', 'b']]
|
35
|
+
@response.set_data(@data)
|
36
|
+
end
|
37
|
+
|
38
|
+
should "set the data for the response" do
|
39
|
+
assert_equal @data, @response.data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestResponseCsv < Test::Unit::TestCase
|
4
|
+
context "the Hotwire::Response::Csv instance" do
|
5
|
+
|
6
|
+
context "created from a valid request" do
|
7
|
+
setup { @response = Hotwire::Response.from_request(valid_request(:out => 'csv')) }
|
8
|
+
|
9
|
+
context "with valid data" do
|
10
|
+
setup do
|
11
|
+
@response.add_column("string", :label => "Column A")
|
12
|
+
@response.set_data([["a1"]])
|
13
|
+
end
|
14
|
+
|
15
|
+
context "body" do
|
16
|
+
should "return csv" do
|
17
|
+
expected = "Column A\na1\n"
|
18
|
+
assert_equal expected, @response.body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestResponseHtml < Test::Unit::TestCase
|
4
|
+
context "the Hotwire::Response::Html instance" do
|
5
|
+
|
6
|
+
context "created from a valid request" do
|
7
|
+
setup { @response = Hotwire::Response.from_request(valid_request(:out => 'html')) }
|
8
|
+
|
9
|
+
context "with valid data" do
|
10
|
+
setup do
|
11
|
+
@response.add_column("string", :label => "Column A")
|
12
|
+
@response.set_data([["a1"]])
|
13
|
+
end
|
14
|
+
|
15
|
+
context "body" do
|
16
|
+
should "return html" do
|
17
|
+
assert !@response.body
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestResponseInvalid < Test::Unit::TestCase
|
4
|
+
context "the Hotwire::Response::Invalid instance" do
|
5
|
+
|
6
|
+
context "created from a valid request" do
|
7
|
+
setup { @response = Hotwire::Response.from_request(valid_request(:out => 'invalid')) }
|
8
|
+
|
9
|
+
context "with valid data" do
|
10
|
+
setup do
|
11
|
+
@response.add_column("string", :label => "Column A")
|
12
|
+
@response.set_data([["a1"]])
|
13
|
+
end
|
14
|
+
|
15
|
+
should "not be valid" do
|
16
|
+
assert !@response.valid?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestResponseJson < Test::Unit::TestCase
|
4
|
+
context "the Hotwire::Response::Json instance" do
|
5
|
+
|
6
|
+
context "created from a valid request" do
|
7
|
+
setup { @response = Hotwire::Response.from_request(valid_request(:out => 'json')) }
|
8
|
+
|
9
|
+
context "with valid data" do
|
10
|
+
setup do
|
11
|
+
@response.add_column("string", :label => "Column A")
|
12
|
+
@response.set_data([["a1"]])
|
13
|
+
end
|
14
|
+
|
15
|
+
context "body" do
|
16
|
+
should "return valid wire json, wrapped in the response handler" do
|
17
|
+
assert_match /^google.visualization.Query.setResponse\(\{.+\}\)$/, @response.body
|
18
|
+
assert_match /\"table\":\{.+\}/, @response.body
|
19
|
+
assert_match /\"rows\":\[\{\"c\":\[\{\"v\":\"a1\"\}\]\}\]/, @response.body
|
20
|
+
assert_match /\"cols\":\[\{\"type\":\"string\",\"label\":\"Column A\"\}\]/, @response.body
|
21
|
+
assert_match /\"status\":\"ok\"/, @response.body
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -1,65 +1,61 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'active_record_test_helper'
|
3
|
-
|
4
|
-
|
5
|
-
class TestActiveRecordMixin < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
1
|
+
# require 'test_helper'
|
2
|
+
# require 'active_record_test_helper'
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# class TestActiveRecordMixin < Test::Unit::TestCase
|
6
|
+
#
|
7
|
+
# context "a Hotwire::Table instance from an ActiveRecord collection" do
|
8
|
+
# setup do
|
9
|
+
# Person.delete_all
|
10
|
+
# Person.create(:name => "Bob", :age => 33, :bio => "A nice Guy", :birth_date => Time.utc(2010, 10, 19, 9, 38, 10))
|
11
|
+
# @data = Hotwire::Table.new(Person.all)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# context "to_wire" do
|
15
|
+
# should "return a properly formatted hash" do
|
16
|
+
# expected = { "table"=> {"rows"=> [{"c"=> [{"v"=>33},
|
17
|
+
# {"v"=>"A nice Guy"},
|
18
|
+
# {"v"=>"Date(2010, 9, 19, 9, 38, 10)"},
|
19
|
+
# {"v"=>"Bob"}]}],
|
20
|
+
# "cols"=> [{"type"=>"number", "id"=>"age", "label"=>"Age"},
|
21
|
+
# {"type"=>"string", "id"=>"bio", "label"=>"Bio"},
|
22
|
+
# {"type"=>"datetime", "id"=>"birth_date", "label"=>"Birth date"},
|
23
|
+
# {"type"=>"string", "id"=>"name", "label"=>"Name"}]}}
|
24
|
+
#
|
25
|
+
# assert_equal expected, @data.to_wire
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# context "an Array of ActiveRecord objects" do
|
31
|
+
# setup do
|
32
|
+
# Person.delete_all
|
33
|
+
# Person.create(:name => "Bob", :age => 33, :bio => "A nice Guy", :birth_date => Time.utc(2010, 10, 19, 9, 38, 10))
|
34
|
+
# @people = Person.all
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# context "to_wire" do
|
38
|
+
# should "return a properly formatted hash" do
|
39
|
+
# expected = { "table"=> {"rows"=> [{"c"=> [{"v"=>33},
|
40
|
+
# {"v"=>"A nice Guy"},
|
41
|
+
# {"v"=>"Date(2010, 9, 19, 9, 38, 10)"},
|
42
|
+
# {"v"=>"Bob"}]}],
|
43
|
+
# "cols"=> [{"type"=>"number", "id"=>"age", "label"=>"Age"},
|
44
|
+
# {"type"=>"string", "id"=>"bio", "label"=>"Bio"},
|
45
|
+
# {"type"=>"datetime", "id"=>"birth_date", "label"=>"Birth date"},
|
46
|
+
# {"type"=>"string", "id"=>"name", "label"=>"Name"}]}}
|
47
|
+
#
|
48
|
+
# assert_equal expected, @people.to_wire
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# context "an Array of non-ActiveRecord objects" do
|
54
|
+
# should "raise an error" do
|
55
|
+
# assert_raises RuntimeError do
|
56
|
+
# ["string"].to_wire
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# end
|
data/test/test_helper.rb
CHANGED
@@ -2,6 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'test/unit'
|
3
3
|
require 'shoulda'
|
4
4
|
require 'redgreen' unless ENV['TM_MODE']
|
5
|
+
require 'mocha'
|
5
6
|
|
6
7
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
8
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
@@ -11,4 +12,15 @@ require 'active_record'
|
|
11
12
|
require 'hotwire'
|
12
13
|
|
13
14
|
class Test::Unit::TestCase
|
15
|
+
def default_tqx_options
|
16
|
+
{:reqId => 0}
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_request tqx_options = {}
|
20
|
+
tqx = default_tqx_options.update(tqx_options).map { |key, val|
|
21
|
+
"#{key}:#{val}"
|
22
|
+
}.join(";")
|
23
|
+
Hotwire::Request.from_params({:tqx => tqx})
|
24
|
+
end
|
25
|
+
|
14
26
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestRequest < Test::Unit::TestCase
|
4
|
+
context "a Hotwire::Request instance" do
|
5
|
+
|
6
|
+
context "created from params with a valid tqx" do
|
7
|
+
setup { @request = Hotwire::Request.from_params({:tqx => "reqId:0;version:0.5"}) }
|
8
|
+
should "be valid" do
|
9
|
+
assert @request.valid?
|
10
|
+
end
|
11
|
+
|
12
|
+
should "allow for params to be get and set via [] and []=" do
|
13
|
+
@request[:reqId] = 3
|
14
|
+
assert_equal 3, @request[:reqId]
|
15
|
+
end
|
16
|
+
|
17
|
+
should "have a default value of 'json' for :out" do
|
18
|
+
assert_equal 'json', @request[:out]
|
19
|
+
end
|
20
|
+
|
21
|
+
context "build_response" do
|
22
|
+
should "wrap Hotwire::Response.from_request" do
|
23
|
+
Hotwire::Response.expects(:from_request).with(@request)
|
24
|
+
@request.build_response
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "created from params without an unsupported version" do
|
30
|
+
setup { @request = Hotwire::Request.from_params({:tqx => "reqId:0;version:99"}) }
|
31
|
+
should "not be valid" do
|
32
|
+
assert !@request.valid?
|
33
|
+
assert !@request.errors.empty?
|
34
|
+
assert @request.errors.to_s.include?("Unsupported version 99")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "created from params without a reqID" do
|
39
|
+
setup { @request = Hotwire::Request.from_params({:tqx => "someParam"}) }
|
40
|
+
should "not be valid" do
|
41
|
+
assert !@request.valid?
|
42
|
+
assert !@request.errors.empty?
|
43
|
+
assert @request.errors.to_s.include?("Missing required parameter reqId")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "created from params without tqx" do
|
48
|
+
setup { @request = Hotwire::Request.from_params({}) }
|
49
|
+
should "be false" do
|
50
|
+
assert_equal false, @request
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|