hotwire 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -59,6 +59,10 @@ The following is a basic example of use.
59
59
  end
60
60
  end
61
61
 
62
+ ## Alternate Data Structures ##
63
+
64
+ The set\_data method on a Hotwire::Response object can be called with several different data structures in order to make getting data into the response as smoothly as possible. See the documentation for Hotwire::Response.set\_data for more details.
65
+
62
66
  ## ActiveRecord ##
63
67
 
64
68
  If your project includes ActiveRecord, Hotwire will automatically included an ActiveRecord mixin that allows columns to be added from a model class.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{hotwire}
8
- s.version = "0.1.1"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Les Freeman"]
12
- s.date = %q{2010-10-25}
12
+ s.date = %q{2010-11-02}
13
13
  s.description = %q{Hotwire is designed to ease the pain of creating Google Wire protocol compatible data source in Ruby.}
14
14
  s.email = %q{les@codebenders.com}
15
15
  s.extra_rdoc_files = [
@@ -34,26 +34,113 @@ module Hotwire
34
34
  end
35
35
  alias_method :add_col, :add_column
36
36
 
37
- # Adds an array of columns to the visualization:
38
- # add_columns(['string', {:id => 'Column A'}], ['number', {:id => 'Column B'}])
37
+ # Adds a colleciton of columns to the visualization
38
+ # +columns+ can either be an array of column definitions:
39
+ # add_columns(['string', {:id => 'Column A'}], ['number', {:id => 'Column B'}])
40
+ #
41
+ # or a sample row of data, represented as a hash keyed as column_name => value:
42
+ # add_columns({:column_a => 'a1', :column_b => 'b1})
43
+ # column_name keys are expected to be symbols(string keys do not maintain order).
39
44
  def add_columns(columns)
40
- columns.each { |col| add_column(*col)}
45
+ if columns.first.is_a?(Hash)
46
+ add_columns_from_data_hash(columns)
47
+ else
48
+ add_columns_from_array(columns)
49
+ end
41
50
  end
42
51
 
43
- # Sets the data to be exported. +data+ should be a 2-dimensional array. The
44
- # first index should iterate over rows, the second over columns. Column
45
- # ordering must be the same used in +add_col+ invokations.
46
- #
47
- # Anything that behaves like a 2-dimensional array and supports +each+ is
52
+ # Sets the data to be exported.
53
+ # +data+ can be a 2-dimensional array of plain data, an array of hashes that are keyed
54
+ # column_name => value, or a hash with a :columns key and a :rows key
55
+ #
56
+ # If passing a 2-dimensional array, the first index should iterate over rows,
57
+ # the second over columns. Column ordering must be the same used in +add_col+
58
+ # invokations. Anything that behaves like a 2-dimensional array and supports +each+ is
48
59
  # a perfectly fine alternative.
60
+ #
61
+ # If passing an array of column_name => value hashes and no columns have been added,
62
+ # a column will automatically be added for each entry in the first row of data.
63
+ # If columns have already been added then the data will be filtered to those
64
+ # columns. column_name keys are expected to be symbols(string keys do not maintain order).
65
+ #
66
+ # If passing a hash with :columns key and a :rows key,
67
+ # :columns should be an array of column ids: ['col_a', 'col_b'...'col_N']
68
+ # :rows should be a 2-dimensional array of data: [['a1', 'b1']...['aN', 'bN']]
69
+ # Note that each row of data must be in the same order as the column id array.
49
70
  def set_data(data)
50
- @data = data
71
+ if data.is_a?(Hash)
72
+ set_data_from_hash(data)
73
+ elsif data.first.is_a?(Hash)
74
+ set_data_from_array_of_hashes(data)
75
+ else
76
+ set_data_from_array(data)
77
+ end
51
78
  return self
52
79
  end
53
80
 
54
81
  # Placeholder method for the subclasses to overwrite
55
82
  def body
56
83
  end
84
+
85
+ protected
86
+
87
+ # Adds columns to the response based on a sample row of data in the form of a hash
88
+ # keyed as column_name => value
89
+ def add_columns_from_data_hash(data)
90
+ data.first.each do |key, value|
91
+ add_column(column_type_for_value(value), :id => key.to_s, :label => key.to_s)
92
+ end
93
+ end
94
+
95
+ # Determines the appropriate Wire Protocol column type for +value+
96
+ def column_type_for_value(value)
97
+ case value.class.name
98
+ when 'BigDecimal', 'Fixnum', 'Float'
99
+ 'number'
100
+ when /Time/
101
+ 'datetime'
102
+ when 'Date'
103
+ 'date'
104
+ when 'String'
105
+ 'string'
106
+ else
107
+ 'string'
108
+ end
109
+ end
110
+
111
+ # Adds multiple columns to the response from an array of column definitions:
112
+ # add_columns(['string', {:id => 'Column A'}], ['number', {:id => 'Column B'}])
113
+ def add_columns_from_array(columns)
114
+ columns.each { |col| add_column(*col)}
115
+ end
116
+
117
+ # Sets up the response based on a hash that has a :columns key and a :rows key.
118
+ # :columns should be an array of column ids: ['col_a', 'col_b'...'col_N']
119
+ # :rows should be a 2-dimensional array of data: [['a1', 'b1']...['aN', 'bN']]
120
+ # This method adds columns based on the first row of data and the provided
121
+ # array of column ids. Note that each row of data must be in the same
122
+ # order as the column id array.
123
+ def set_data_from_hash(data)
124
+ data[:columns].each_with_index do |column_name, index|
125
+ sample_value = data[:rows].first[index]
126
+ add_column(column_type_for_value(sample_value), :id => column_name, :label => column_name)
127
+ end
128
+ set_data_from_array(data[:rows])
129
+ end
130
+
131
+ # Sets the response data from an array of row hashes that are keyed column_name => value.
132
+ # If there are no columns setup, they are added automatically.
133
+ # Data is filtered on the columns that exist.
134
+ def set_data_from_array_of_hashes(data)
135
+ add_columns(data) if columns.empty?
136
+ set_data(data.map { |row| self.columns.map { |c| row[c[:id].to_sym] } })
137
+ end
138
+
139
+ # Sets the response data from a two dimensional array of innumerables.
140
+ def set_data_from_array(data)
141
+ @data = data
142
+ end
143
+
57
144
  end
58
145
 
59
146
  end
@@ -39,14 +39,76 @@ class TestResponseBase < Test::Unit::TestCase
39
39
  end
40
40
 
41
41
  context "set_data" do
42
- setup do
43
- @data = [['a', 'b']]
44
- @response.set_data(@data)
42
+ context "from an array of hashes" do
43
+ context "when columns are not set" do
44
+ setup do
45
+ @datetime = Time.utc(2010, 11, 2, 9, 35, 00)
46
+ @data = [{:string_col => 'a1', :int_col => 2, :decimal_col => 3.3, :datetime_col => @datetime}]
47
+ @response.set_data(@data)
48
+ end
49
+ should "add columns to the response" do
50
+ expected = [{:id => 'string_col', :label => "string_col", :type => 'string'},
51
+ {:id => 'int_col', :label => "int_col", :type => 'number'},
52
+ {:id => 'decimal_col', :label => "decimal_col", :type => 'number'},
53
+ {:id => 'datetime_col', :label => "datetime_col", :type => 'datetime'}]
54
+ assert_equal expected, @response.columns
55
+ end
56
+ should "set the data for the response" do
57
+ assert_equal [['a1', 2, 3.3, @datetime]], @response.data
58
+ end
59
+ end
60
+
61
+ context "when columns are already set" do
62
+ setup do
63
+ @data = [{:col_a => 'a1', :col_b => 'b1', :col_c => 'c1'}]
64
+ @response.add_columns([['string', {:id => 'col_c', :label => 'col_c'}],
65
+ ['string', {:id => 'col_a', :label => 'col_a'}]])
66
+ @response.set_data(@data)
67
+ end
68
+ should "add columns to the response" do
69
+ expected = [{:id => 'col_c', :label => "col_c", :type => 'string'},
70
+ {:id => 'col_a', :label => "col_a", :type => 'string'}]
71
+ assert_equal expected, @response.columns
72
+ end
73
+ should "set the data for the response" do
74
+ assert_equal [['c1', 'a1']], @response.data
75
+ end
76
+ end
45
77
  end
46
78
 
47
- should "set the data for the response" do
48
- assert_equal @data, @response.data
79
+ context "from a :rows, :columns hash" do
80
+ setup do
81
+ @datetime = Time.utc(2010, 11, 2, 9, 35, 00)
82
+ @data = {:columns => ["string_col", "int_col", "decimal_col", "datetime_col"],
83
+ :rows => [['a1', 2, 3.3, @datetime]]}
84
+ @response.set_data(@data)
85
+ end
86
+
87
+ should "add columns to the response" do
88
+ expected = [{:id => 'string_col', :label => "string_col", :type => 'string'},
89
+ {:id => 'int_col', :label => "int_col", :type => 'number'},
90
+ {:id => 'decimal_col', :label => "decimal_col", :type => 'number'},
91
+ {:id => 'datetime_col', :label => "datetime_col", :type => 'datetime'}]
92
+ assert_equal expected, @response.columns
93
+ end
94
+
95
+ should "set the data from the response" do
96
+ assert_equal [['a1', 2, 3.3, @datetime]], @response.data
97
+ end
98
+ end
99
+
100
+ context "from an array of arrays" do
101
+ setup do
102
+ @data = [['a', 'b']]
103
+ @response.set_data(@data)
104
+ end
105
+
106
+ should "set the data for the response" do
107
+ assert_equal @data, @response.data
108
+ end
49
109
  end
110
+
111
+
50
112
  end
51
113
 
52
114
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hotwire
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Les Freeman
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-25 00:00:00 -07:00
18
+ date: 2010-11-02 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency