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.
- data/.gitignore +4 -0
- data/LICENSE +19 -0
- data/README.rdoc +61 -0
- data/Rakefile +25 -0
- data/btucker-google_visualization.gemspec +86 -0
- data/lib/google_visualization.rb +33 -0
- data/lib/google_visualization/data_cell.rb +53 -0
- data/lib/google_visualization/data_column.rb +100 -0
- data/lib/google_visualization/data_element.rb +59 -0
- data/lib/google_visualization/data_row.rb +79 -0
- data/lib/google_visualization/data_table.rb +142 -0
- data/lib/google_visualization/data_type.rb +38 -0
- data/lib/google_visualization/formatter.rb +15 -0
- data/lib/google_visualization/formatter/csv.rb +31 -0
- data/lib/google_visualization/formatter/json.rb +90 -0
- data/tasks/ftp.rake +182 -0
- data/tasks/rdoc.rake +11 -0
- data/tasks/test.rake +13 -0
- data/test/data/table1.json +1 -0
- data/test/data/table1.rb +1 -0
- data/test/data/table2.json +1 -0
- data/test/data/table2.rb +8 -0
- data/test/data/table3.json +1 -0
- data/test/data/table3.rb +8 -0
- data/test/data/table4.json +1 -0
- data/test/data/table4.rb +8 -0
- data/test/helper.rb +4 -0
- data/test/tc_data_cell.rb +44 -0
- data/test/tc_data_column.rb +76 -0
- data/test/tc_data_element.rb +31 -0
- data/test/tc_data_row.rb +49 -0
- data/test/tc_data_table.rb +124 -0
- data/test/tc_data_type.rb +28 -0
- metadata +117 -0
|
@@ -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,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
|
data/tasks/ftp.rake
ADDED
|
@@ -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
|