btucker-google_visualization 0.5.3

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.
@@ -0,0 +1,79 @@
1
+ module Google
2
+ module Visualization
3
+
4
+ ##
5
+ # = DataRow
6
+ #
7
+ # == Description
8
+ #
9
+ # Represents a row of data in a DataTable.
10
+ #
11
+ class DataRow < DataElement
12
+
13
+ ##
14
+ # Creates a new row.
15
+ #
16
+ def initialize(cells=[])
17
+ super()
18
+ @closed = false
19
+ @cells = []
20
+ add_cells(cells) unless (cells.nil? or cells.empty?)
21
+ end
22
+
23
+ ##
24
+ # Returns the number of cells.
25
+ #
26
+ def cells_count
27
+ @cells.size
28
+ end
29
+
30
+ ##
31
+ # Returns the cell at index.
32
+ #
33
+ def cell(index)
34
+ @cells[index]
35
+ end
36
+
37
+ ##
38
+ # Returns a enumerable of all cells.
39
+ #
40
+ def cells
41
+ @cells.to_enum
42
+ end
43
+
44
+ ##
45
+ # Adds a single object to the end of the row and returns self.
46
+ #
47
+ def add_cell(obj)
48
+ raise(StandardError, "can't modify closed row") if @closed
49
+ obj = DataCell.new(obj) unless obj.is_a?(DataCell)
50
+ @cells << obj
51
+ self
52
+ end
53
+
54
+ ##
55
+ # Adds multiple objects to the end of the row and returns self.
56
+ #
57
+ def add_cells(list)
58
+ list.each { |obj| add_cell(obj) }
59
+ self
60
+ end
61
+
62
+ ##
63
+ # Prevents new cells from being added.
64
+ #
65
+ def close
66
+ @closed = true
67
+ end
68
+
69
+ ##
70
+ # Returns true if closed.
71
+ #
72
+ def closed?
73
+ @closed
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,142 @@
1
+ module Google
2
+ module Visualization
3
+
4
+ ##
5
+ # = DataTable
6
+ #
7
+ # == Description
8
+ #
9
+ # Represents a two-dimensional, mutable table of values.
10
+ #
11
+ class DataTable < DataElement
12
+
13
+ ##
14
+ # Creates a new table.
15
+ #
16
+ def initialize(columns=[], rows=[])
17
+ super()
18
+ @columns = []
19
+ @rows = []
20
+ add_columns(columns) unless (columns.nil? or columns.empty?)
21
+ add_rows(rows) unless (rows.nil? or rows.empty?)
22
+ end
23
+
24
+ ##
25
+ # Returns the number of rows.
26
+ #
27
+ def rows_count
28
+ @rows.size
29
+ end
30
+
31
+ ##
32
+ # Returns the number of columns.
33
+ #
34
+ def columns_count
35
+ @columns.size
36
+ end
37
+
38
+ ##
39
+ # Returns the row at index.
40
+ #
41
+ def row(index)
42
+ @rows[index]
43
+ end
44
+
45
+ ##
46
+ # Returns the column at index.
47
+ #
48
+ def column(index)
49
+ @columns[index]
50
+ end
51
+
52
+ ##
53
+ # Returns the cell at index.
54
+ #
55
+ def cell(row_index, column_index)
56
+ row(row_index).cell(column_index)
57
+ end
58
+
59
+ ##
60
+ # Returns a enumerable of all rows.
61
+ #
62
+ def rows
63
+ @rows.to_enum
64
+ end
65
+
66
+ ##
67
+ # Returns a enumerable of all columns.
68
+ #
69
+ def columns
70
+ @columns.to_enum
71
+ end
72
+
73
+ ##
74
+ # Adds a single row to the end of the table and returns self.
75
+ #
76
+ def add_row(obj)
77
+ obj = DataRow.new(obj) unless obj.is_a?(DataRow)
78
+ raise(StandardError, "wrong row size #{obj.cells_count}, should be #{columns_count})") if obj.cells_count != columns_count
79
+ obj.close
80
+ @rows << obj
81
+ self
82
+ end
83
+
84
+ ##
85
+ # Adds a single column to the end of the table and returns self.
86
+ #
87
+ def add_column(obj)
88
+ raise(StandardError, "can't add columns after adding rows") if rows_count > 0
89
+ obj = DataColumn.new(obj) unless obj.is_a?(DataColumn)
90
+ obj.close
91
+ @columns << obj
92
+ self
93
+ end
94
+
95
+ ##
96
+ # Adds multiple rows to the end of the table and returns self.
97
+ #
98
+ def add_rows(list)
99
+ list.each { |obj| add_row(obj) }
100
+ self
101
+ end
102
+
103
+ ##
104
+ # Adds multiple columns to the end of the table and returns self.
105
+ #
106
+ def add_columns(list)
107
+ list.each { |obj| add_column(obj) }
108
+ self
109
+ end
110
+
111
+ ##
112
+ # Sorts the table rows according to the specified order and columns.
113
+ #
114
+ def sort_rows!(order, *columns)
115
+ correlation = (order == :ascending ? 1 : -1)
116
+ @rows.sort! { |a,b|
117
+ pivot = 0
118
+ columns.each { |column|
119
+ pivot = column
120
+ break if a.cell(column).value != b.cell(column).value
121
+ }
122
+ (a.cell(pivot).value <=> b.cell(pivot).value) * correlation
123
+ }
124
+ end
125
+
126
+ ##
127
+ # Returns a JSON representation of the table, according to the Google Visualization API.
128
+ #
129
+ def to_json
130
+ Formatter::JSON.render(self)
131
+ end
132
+
133
+ ##
134
+ # Returns a CSV representation of the table, according to the Google Visualization API.
135
+ #
136
+ def to_csv
137
+ Formatter::CSV.render(self)
138
+ end
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,38 @@
1
+ module Google
2
+ module Visualization
3
+
4
+ ##
5
+ # = DataType
6
+ #
7
+ # == Description
8
+ #
9
+ # Represents a data type for a DataColumn.
10
+ #
11
+ class DataType
12
+
13
+ ##
14
+ # Creates a new type.
15
+ #
16
+ def initialize(name)
17
+ @name = name
18
+ end
19
+
20
+ ##
21
+ # Returns a string representing the type.
22
+ #
23
+ def to_s
24
+ @name.to_s
25
+ end
26
+
27
+ STRING = DataType.new(:string)
28
+ NUMBER = DataType.new(:number)
29
+ BOOLEAN = DataType.new(:boolean)
30
+ DATE = DataType.new(:date)
31
+ DATETIME = DataType.new(:datetime)
32
+ TIMEOFDAY = DataType.new(:timeofday)
33
+
34
+ private_class_method :new
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ module Google
2
+ module Visualization
3
+
4
+ ##
5
+ # = Formatter
6
+ #
7
+ # == Description
8
+ #
9
+ # The Google::Visualization::Formatter module contains classes that can be used for serializing a DataTable.
10
+ #
11
+ module Formatter
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ require 'csv'
2
+
3
+ module Google
4
+ module Visualization
5
+ module Formatter
6
+
7
+ ##
8
+ # = JSON Formatter
9
+ #
10
+ # == Description
11
+ #
12
+ # Serializes a DataTable to Comma Separated values (CSV)
13
+ class CSV
14
+ private_class_method :new
15
+ ##
16
+ # Generates a JSON string representation of a data table.
17
+ #
18
+ def self.render(data_table)
19
+ output = ""
20
+ ::CSV::Writer.generate(output) do |csv|
21
+ csv << data_table.columns.map(&:label)
22
+ data_table.rows.each do |row|
23
+ csv << row.cells.map(&:value)
24
+ end
25
+ end
26
+ output
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,90 @@
1
+ require 'json'
2
+
3
+ module Google
4
+ module Visualization
5
+ module Formatter
6
+
7
+ ##
8
+ # = JSON Formatter
9
+ #
10
+ # == Description
11
+ #
12
+ # Serializes a DataTable to the JavaScript Object Notation (JSON).
13
+ #
14
+ class JSON
15
+
16
+ private_class_method :new
17
+
18
+ ##
19
+ # Generates a JSON string representation of a data table.
20
+ #
21
+ def self.render(data_table)
22
+ {
23
+ 'cols' => render_columns(data_table),
24
+ 'rows' => render_rows(data_table) #,
25
+ # 'p' => render_custom_properties(data_table)
26
+ }.to_json
27
+ end
28
+
29
+ private
30
+
31
+ ##
32
+ # Generates a JSON string representation of a multiple columns.
33
+ #
34
+ def self.render_columns(data_table)
35
+ data_table.columns.map{|c| render_column(c)}
36
+ end
37
+
38
+ ##
39
+ # Generates a JSON string representation of a single column.
40
+ #
41
+ def self.render_column(column)
42
+ result = {}
43
+ %w(id label type pattern).each do |field|
44
+ result[field] = column.send(field).to_s if column.send(field)
45
+ end
46
+ # if column.custom_properties_count > 0
47
+ # result["p"] = render_custom_properties(column)
48
+ # end
49
+ result
50
+ end
51
+
52
+ ##
53
+ # Generates a JSON string representation of multiple rows.
54
+ #
55
+ def self.render_rows(data_table)
56
+ data_table.rows.map{|r| render_row(r, data_table)}
57
+ end
58
+
59
+ ##
60
+ # Generates a JSON string representation of a single row.
61
+ #
62
+ def self.render_row(row, data_table)
63
+ result = {'c' => []}
64
+ result = {'c' => row.cells.map {|c| render_cell(c)}}
65
+ result
66
+ end
67
+
68
+ ##
69
+ # Generates a JSON string representation of a cell.
70
+ #
71
+ def self.render_cell(cell)
72
+ result = {'v' => cell.value}
73
+ result['f'] = cell.formatted_value if cell.formatted_value
74
+ # result['p'] = render_custom_properties(row) if row.custom_properties_count > 0
75
+ result
76
+ end
77
+
78
+ ##
79
+ # Generates a JSON string representation of the custom properties.
80
+ #
81
+ #def self.render_custom_properties(data_element)
82
+ # result = data_element.custom_properties.collect { |name,value|
83
+ # "#{name.to_s}:#{rb_to_js(value, DataType::STRING)}"
84
+ # }
85
+ # "p:{#{result.join(',')}}"
86
+ #end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,182 @@
1
+ require 'net/ftp'
2
+ require 'pathname'
3
+ require 'yaml'
4
+ require 'rake'
5
+ require 'rake/tasklib'
6
+
7
+ module Rake
8
+
9
+ # = FTPTask
10
+ #
11
+ # == Description
12
+ # A Rake task that transfers local files to an FTP server.
13
+ #
14
+ # == Usage
15
+ # Rake::FTPTask.new do |t|
16
+ # t.host = "ftp.example.com"
17
+ # t.user_name = "user"
18
+ # t.password = "pass"
19
+ # t.path = "public_html/"
20
+ # t.upload_files = FileList["doc/**/*"].to_a
21
+ # end
22
+ #
23
+ # To avoid hard-coding the connection configuration into the source code, the task can obtain that data from a YAML file.
24
+ #
25
+ # Rake::FTPTask.new("ftp.yml") do |t|
26
+ # t.path = "public_html/"
27
+ # t.upload_files = FileList["doc/**/*"].to_a
28
+ # end
29
+ #
30
+ # # ftp.yml
31
+ # host = ftp.example.com
32
+ # user_name = user
33
+ # password = pass
34
+ # path = public_html/
35
+ #
36
+ class FTPTask < TaskLib
37
+
38
+ ##
39
+ # The address of the server (default is nil).
40
+ #
41
+ attr_accessor :host
42
+
43
+ ##
44
+ # The user name required to log into the server (default is "anonymous").
45
+ #
46
+ attr_accessor :user_name
47
+
48
+ ##
49
+ # The password required for the selected user name (default is nil).
50
+ #
51
+ attr_accessor :password
52
+
53
+ ##
54
+ # The (remote) base directory (default is "").
55
+ #
56
+ attr_accessor :path
57
+
58
+ ##
59
+ # The array of files to be included in the FTP upload (default is []).
60
+ #
61
+ attr_accessor :upload_files
62
+
63
+ ##
64
+ # The boolean to enable progress messages when true (default is false).
65
+ #
66
+ attr_accessor :verbose
67
+
68
+ ##
69
+ # Creates a new FTP task.
70
+ #
71
+ def initialize(config_file=nil)
72
+ @host = nil
73
+ @user_name = "anonymous"
74
+ @password = nil
75
+ @path = ""
76
+ @upload_files = []
77
+ @verbose = false
78
+ @ftp = nil
79
+ @history = {}
80
+ load_config(config_file) unless config_file.nil?
81
+ yield self if block_given?
82
+ define
83
+ end
84
+
85
+ ##
86
+ # Creates the tasks defined by this task lib.
87
+ #
88
+ def define
89
+
90
+ namespace :ftp do
91
+ desc "Upload files to an FTP account"
92
+ task(:upload) do
93
+ connect
94
+ upload
95
+ disconnect
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ private
102
+
103
+ ##
104
+ # Reads configuration values from a YAML file.
105
+ #
106
+ def load_config(file)
107
+ config = YAML::load_file(file)
108
+ @host = config["host"] || @host
109
+ @user_name = config["user_name"] || @user_name
110
+ @password = config["password"] || @password
111
+ @path = config["path"] || @path
112
+ end
113
+
114
+ ##
115
+ # Establishes the FTP connection.
116
+ #
117
+ def connect
118
+ @ftp = Net::FTP.new(@host, @user_name, @password)
119
+ puts "Connected to #{@host}" if @verbose
120
+ puts "Using #{@ftp.binary ? "binary" : "text"} mode to transfer files" if @verbose
121
+ unless @path.nil? or @path.empty?
122
+ make_dirs(@path)
123
+ @ftp.chdir(@path)
124
+ puts "The working directory is now #{@ftp.getdir}" if @verbose
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Closes the FTP connection. Further remote operations are impossible.
130
+ #
131
+ def disconnect
132
+ @ftp.close
133
+ puts "Disconnected" if @verbose
134
+ end
135
+
136
+ ##
137
+ # Iterates through the array of files.
138
+ #
139
+ def upload
140
+ puts "Uploading #{@upload_files.length} files..." if @verbose
141
+ @upload_files.each do |entry|
142
+ if File.directory?(entry)
143
+ make_dirs(entry)
144
+ else
145
+ put_file(entry)
146
+ end
147
+ end
148
+ end
149
+
150
+ ##
151
+ # Transfers a local file to the server, relative to the current working directory.
152
+ #
153
+ def put_file(name)
154
+ puts "Uploading file #{name}" if @verbose
155
+ path = File.dirname(name)
156
+ make_dirs(path)
157
+ @ftp.put(name,name)
158
+ end
159
+
160
+ ##
161
+ # Creates a directory and all its parent directories in the server, relative to the current working directory.
162
+ #
163
+ def make_dirs(name)
164
+ Pathname.new(name).descend do |dir|
165
+ if @history[dir].nil?
166
+ @history[dir] = true
167
+ puts "Creating directory #{dir}" if @verbose
168
+ @ftp.mkdir(dir) rescue nil
169
+ end
170
+ end
171
+ end
172
+
173
+ end
174
+
175
+ end
176
+
177
+ if File.exists?("config/ftp.yml")
178
+ Rake::FTPTask.new("config/ftp.yml") do |ftp|
179
+ ftp.upload_files = FileList["doc/**/*"].to_a
180
+ ftp.verbose = true
181
+ end
182
+ end