workbook 0.4.2 → 0.4.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 +2 -1
- data/.yardoc/checksums +22 -21
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/Gemfile.lock +2 -2
- data/doc/RubyXL.html +1 -1
- data/doc/RubyXL/Cell.html +1 -1
- data/doc/RubyXL/Workbook.html +31 -31
- data/doc/Workbook.html +4 -4
- data/doc/Workbook/Book.html +5 -5
- data/doc/Workbook/Cell.html +202 -62
- data/doc/Workbook/Format.html +32 -32
- data/doc/Workbook/Modules.html +1 -1
- data/doc/Workbook/Modules/RawObjectsStorage.html +5 -5
- data/doc/Workbook/Modules/TableDiffSort.html +14 -14
- data/doc/Workbook/Modules/TypeParser.html +7 -7
- data/doc/Workbook/NilValue.html +434 -0
- data/doc/Workbook/Readers.html +3 -3
- data/doc/Workbook/Readers/CsvReader.html +6 -6
- data/doc/Workbook/Readers/OdsReader.html +562 -60
- data/doc/Workbook/Readers/TxtReader.html +2 -2
- data/doc/Workbook/Readers/XlsReader.html +14 -14
- data/doc/Workbook/Readers/XlsShared.html +67 -67
- data/doc/Workbook/Readers/XlsxReader.html +7 -7
- data/doc/Workbook/Row.html +243 -5
- data/doc/Workbook/Sheet.html +2 -2
- data/doc/Workbook/Table.html +669 -58
- data/doc/Workbook/Template.html +5 -5
- data/doc/Workbook/Writers.html +1 -1
- data/doc/Workbook/Writers/CsvTableWriter.html +1 -1
- data/doc/Workbook/Writers/HtmlWriter.html +27 -13
- data/doc/Workbook/Writers/XlsWriter.html +2 -2
- data/doc/_index.html +23 -8
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +16 -12
- data/doc/index.html +16 -12
- data/doc/method_list.html +232 -72
- data/doc/top-level-namespace.html +1 -1
- data/lib/workbook/book.rb +25 -25
- data/lib/workbook/cell.rb +33 -33
- data/lib/workbook/format.rb +10 -10
- data/lib/workbook/modules/raw_objects_storage.rb +19 -19
- data/lib/workbook/modules/table_diff_sort.rb +22 -22
- data/lib/workbook/modules/type_parser.rb +18 -18
- data/lib/workbook/nil_value.rb +6 -6
- data/lib/workbook/readers/csv_reader.rb +8 -8
- data/lib/workbook/readers/ods_reader.rb +92 -46
- data/lib/workbook/readers/txt_reader.rb +2 -2
- data/lib/workbook/readers/xls_reader.rb +19 -19
- data/lib/workbook/readers/xls_shared.rb +70 -70
- data/lib/workbook/readers/xlsx_reader.rb +42 -42
- data/lib/workbook/row.rb +59 -29
- data/lib/workbook/sheet.rb +8 -8
- data/lib/workbook/table.rb +52 -19
- data/lib/workbook/template.rb +10 -10
- data/lib/workbook/version.rb +1 -1
- data/lib/workbook/writers/csv_table_writer.rb +1 -1
- data/lib/workbook/writers/html_writer.rb +6 -6
- data/lib/workbook/writers/xls_writer.rb +12 -12
- data/rbeautify.rb +232 -0
- data/test/artifacts/book_with_colspans.ods +0 -0
- data/test/artifacts/book_with_tabs_and_colours.ods +0 -0
- data/test/test_book.rb +10 -10
- data/test/test_cell.rb +14 -14
- data/test/test_format.rb +11 -11
- data/test/test_functional.rb +3 -3
- data/test/test_modules_table_diff_sort.rb +24 -24
- data/test/test_modules_type_parser.rb +27 -27
- data/test/test_readers_csv_reader.rb +11 -11
- data/test/test_readers_ods_reader.rb +22 -15
- data/test/test_readers_txt_reader.rb +13 -13
- data/test/test_readers_xls_reader.rb +11 -11
- data/test/test_readers_xlsx_reader.rb +5 -5
- data/test/test_row.rb +96 -26
- data/test/test_sheet.rb +9 -9
- data/test/test_table.rb +42 -26
- data/test/test_template.rb +3 -3
- data/test/test_writers_html_writer.rb +6 -4
- data/test/test_writers_xls_writer.rb +7 -7
- metadata +5 -1
data/lib/workbook/sheet.rb
CHANGED
@@ -4,7 +4,7 @@ module Workbook
|
|
4
4
|
# A Sheet is a container of tables
|
5
5
|
attr_accessor :book
|
6
6
|
attr_accessor :name
|
7
|
-
|
7
|
+
|
8
8
|
# Initialize a new sheet
|
9
9
|
#
|
10
10
|
# @param [Workbook::Table, Array<Array>] table The first table of this sheet
|
@@ -20,14 +20,14 @@ module Workbook
|
|
20
20
|
self.book = book
|
21
21
|
return self
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
# Returns true if the first table of this sheet contains anything
|
25
25
|
#
|
26
26
|
# @return [Boolean]
|
27
27
|
def has_contents?
|
28
28
|
table.has_contents?
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
# Returns the first table of this sheet
|
32
32
|
#
|
33
33
|
# @return [Workbook::Table] the first table of this sheet
|
@@ -46,14 +46,14 @@ module Workbook
|
|
46
46
|
return @book
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
# Removes all lines from this table
|
51
51
|
#
|
52
52
|
# @return [Workbook::Table] (self)
|
53
53
|
def delete_all
|
54
54
|
self.delete_if{|b| true}
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# clones itself *and* the tables it contains
|
58
58
|
#
|
59
59
|
# @return [Workbook::Sheet] The cloned sheet
|
@@ -64,15 +64,15 @@ module Workbook
|
|
64
64
|
s.each{|t| c << t.clone}
|
65
65
|
return c
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# Create or open the existing table at an index value
|
69
|
-
#
|
69
|
+
#
|
70
70
|
# @param [Integer] index the index of the table
|
71
71
|
def create_or_open_table_at index
|
72
72
|
t = self[index]
|
73
73
|
t = self[index] = Workbook::Table.new if t == nil
|
74
74
|
t.sheet = self
|
75
|
-
t
|
75
|
+
t
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
data/lib/workbook/table.rb
CHANGED
@@ -3,7 +3,7 @@ require 'workbook/modules/table_diff_sort'
|
|
3
3
|
require 'workbook/writers/csv_table_writer'
|
4
4
|
|
5
5
|
|
6
|
-
module Workbook
|
6
|
+
module Workbook
|
7
7
|
# A table is a container of rows and keeps track of the sheet it belongs to and which row is its header. Additionally suport for CSV writing and diffing with another table is included.
|
8
8
|
class Table < Array
|
9
9
|
include Workbook::Modules::TableDiffSort
|
@@ -11,7 +11,7 @@ module Workbook
|
|
11
11
|
attr_accessor :sheet
|
12
12
|
attr_accessor :name
|
13
13
|
attr_accessor :header
|
14
|
-
|
14
|
+
|
15
15
|
def initialize row_cel_values=[], sheet=nil, options={}
|
16
16
|
row_cel_values = [] if row_cel_values == nil
|
17
17
|
row_cel_values.each do |r|
|
@@ -24,8 +24,8 @@ module Workbook
|
|
24
24
|
self.sheet = sheet
|
25
25
|
# Column data is considered as a 'row' with 'cells' that contain 'formatting'
|
26
26
|
end
|
27
|
-
|
28
|
-
# Returns the header of this table (typically the first row, but can be a different row).
|
27
|
+
|
28
|
+
# Returns the header of this table (typically the first row, but can be a different row).
|
29
29
|
# The header row is also used for finding values in a aribrary row.
|
30
30
|
#
|
31
31
|
# @return [Workbook::Row] The header
|
@@ -38,33 +38,39 @@ module Workbook
|
|
38
38
|
first
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# Generates a new row, with optionally predefined cell-values, that is already connected to this table.
|
43
43
|
def new_row cell_values=[]
|
44
44
|
r = Workbook::Row.new(cell_values,self)
|
45
45
|
return r
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def create_or_open_row_at index
|
49
49
|
r = self[index]
|
50
50
|
if r == nil
|
51
51
|
r = Workbook::Row.new
|
52
52
|
r.table=(self)
|
53
53
|
end
|
54
|
-
r
|
55
|
-
end
|
56
|
-
|
54
|
+
r
|
55
|
+
end
|
56
|
+
|
57
57
|
def remove_empty_lines!
|
58
58
|
self.delete_if{|r| r.nil? or r.compact.empty?}
|
59
59
|
self
|
60
60
|
end
|
61
61
|
|
62
|
+
# Add row
|
63
|
+
# @param [Workbook::Table, Array] row to add
|
62
64
|
def push(row)
|
65
|
+
row = Workbook::Row.new(row) if row.class == Array
|
63
66
|
super(row)
|
64
67
|
row.set_table(self)
|
65
68
|
end
|
66
|
-
|
69
|
+
|
70
|
+
# Add row
|
71
|
+
# @param [Workbook::Table, Array] row to add
|
67
72
|
def <<(row)
|
73
|
+
row = Workbook::Row.new(row) if row.class == Array
|
68
74
|
super(row)
|
69
75
|
row.set_table(self)
|
70
76
|
end
|
@@ -72,16 +78,16 @@ module Workbook
|
|
72
78
|
def has_contents?
|
73
79
|
self.clone.remove_empty_lines!.count != 0
|
74
80
|
end
|
75
|
-
|
81
|
+
|
76
82
|
# Returns true if the row exists in this table
|
77
83
|
#
|
78
84
|
# @param [Workbook::Row] row to test for
|
79
|
-
# @return [Boolean] whether the row exist in this table
|
85
|
+
# @return [Boolean] whether the row exist in this table
|
80
86
|
def contains_row? row
|
81
87
|
raise ArgumentError, "table should be a Workbook::Row (you passed a #{t.class})" unless row.is_a?(Workbook::Row)
|
82
88
|
self.collect{|r| r.object_id}.include? row.object_id
|
83
89
|
end
|
84
|
-
|
90
|
+
|
85
91
|
# Returns the sheet this table belongs to, creates a new sheet if none exists
|
86
92
|
#
|
87
93
|
# @return [Workbook::Sheet] The sheet this table belongs to
|
@@ -93,14 +99,14 @@ module Workbook
|
|
93
99
|
return @sheet
|
94
100
|
end
|
95
101
|
end
|
96
|
-
|
102
|
+
|
97
103
|
# Removes all lines from this table
|
98
104
|
#
|
99
105
|
# @return [Workbook::Table] (self)
|
100
106
|
def delete_all
|
101
107
|
self.delete_if{|b| true}
|
102
108
|
end
|
103
|
-
|
109
|
+
|
104
110
|
# clones itself *and* the rows it contains
|
105
111
|
#
|
106
112
|
# @return [Workbook::Table] The cloned table
|
@@ -113,7 +119,7 @@ module Workbook
|
|
113
119
|
c.header = c[header_row_index] if header_row_index
|
114
120
|
return c
|
115
121
|
end
|
116
|
-
|
122
|
+
|
117
123
|
# Overrides normal Array's []-function with support for symbols that identify a column based on the header-values
|
118
124
|
#
|
119
125
|
# @example Lookup using fixnum or header value encoded as symbol
|
@@ -128,24 +134,51 @@ module Workbook
|
|
128
134
|
cell_index = alpha_index_to_number_index(match[1])
|
129
135
|
row_index = match[2].to_i - 1
|
130
136
|
return self[row_index][cell_index]
|
131
|
-
else
|
137
|
+
else
|
132
138
|
if index_or_string
|
133
139
|
return to_a[index_or_string]
|
134
140
|
end
|
135
141
|
end
|
136
142
|
end
|
137
|
-
|
143
|
+
|
138
144
|
# Helps to convert from e.g. "AA" to 26
|
139
145
|
# @param [String] string that typically identifies a column
|
140
146
|
# @return [Integer]
|
141
147
|
def alpha_index_to_number_index string
|
142
148
|
string.upcase!
|
143
149
|
sum = 0
|
144
|
-
string.chars.each_with_index do | char, char_index|
|
150
|
+
string.chars.each_with_index do | char, char_index|
|
145
151
|
sum = sum * 26 + char.unpack('U')[0]-64
|
146
152
|
end
|
147
153
|
return sum-1
|
148
154
|
end
|
149
155
|
|
156
|
+
# remove all the trailing empty-rows (returning a trimmed clone)
|
157
|
+
#
|
158
|
+
# @param [Integer] desired_row_length of the rows
|
159
|
+
# @return [Workbook::Row] a trimmed clone of the array
|
160
|
+
def trim(desired_row_length=nil)
|
161
|
+
self.clone.trim!(desired_row_length)
|
162
|
+
end
|
163
|
+
|
164
|
+
# remove all the trailing empty-rows (returning a trimmed self)
|
165
|
+
#
|
166
|
+
# @param [Integer] desired_row_length of the new row
|
167
|
+
# @return [Workbook::Row] self
|
168
|
+
def trim!(desired_row_length=nil)
|
169
|
+
max_length = self.collect{|a| a.trim.length }.max
|
170
|
+
self_count = self.count-1
|
171
|
+
self.count.times do |index|
|
172
|
+
index = self_count - index
|
173
|
+
if self[index].trim.empty?
|
174
|
+
self.delete_at(index)
|
175
|
+
else
|
176
|
+
break
|
177
|
+
end
|
178
|
+
end
|
179
|
+
self.each{|a| a.trim!(max_length)}
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
150
183
|
end
|
151
184
|
end
|
data/lib/workbook/template.rb
CHANGED
@@ -5,18 +5,18 @@ module Workbook
|
|
5
5
|
# Workbook::Template is a container for different Workbook::Format's and the storage of raw template data that isn't really supported by Workbook, but should survive a typical read/write cyclus.
|
6
6
|
class Template
|
7
7
|
include Workbook::Modules::RawObjectsStorage
|
8
|
-
|
8
|
+
|
9
9
|
# Initialize Workbook::Template
|
10
|
-
def initialize
|
10
|
+
def initialize
|
11
11
|
@formats = {}
|
12
12
|
@has_header = true
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
# Whether the template has a predefined header (headers are used )
|
16
16
|
def has_header?
|
17
17
|
@has_header
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# Add a Workbook::Format to the template
|
21
21
|
# @param [Workbook::Format] format (of a cell) to add to the template
|
22
22
|
def add_format format
|
@@ -24,15 +24,15 @@ module Workbook
|
|
24
24
|
@formats[format.name]=format
|
25
25
|
else
|
26
26
|
raise ArgumentError, "format should be a Workboot::Format"
|
27
|
-
end
|
27
|
+
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Return the list of associated formats
|
31
31
|
# @return [Hash] A keyed-hash of named formats
|
32
32
|
def formats
|
33
33
|
@formats
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
# Create or find a format by name
|
37
37
|
# @return [Workbook::Format] The new or found format
|
38
38
|
# @param [String] name of the format (e.g. whatever you want, in diff names such as 'destroyed', 'updated' and 'created' are being used)
|
@@ -41,8 +41,8 @@ module Workbook
|
|
41
41
|
fs = @formats[name]
|
42
42
|
fs = @formats[name] = {} if fs.nil?
|
43
43
|
f = fs[variant]
|
44
|
-
if f.nil?
|
45
|
-
f = Workbook::Format.new
|
44
|
+
if f.nil?
|
45
|
+
f = Workbook::Format.new
|
46
46
|
if variant != :default and fs[:default]
|
47
47
|
f = fs[:default].clone
|
48
48
|
end
|
@@ -50,5 +50,5 @@ module Workbook
|
|
50
50
|
end
|
51
51
|
return @formats[name][variant]
|
52
52
|
end
|
53
|
-
|
53
|
+
end
|
54
54
|
end
|
data/lib/workbook/version.rb
CHANGED
@@ -6,15 +6,15 @@ module Workbook
|
|
6
6
|
module HtmlWriter
|
7
7
|
|
8
8
|
# Generates an Spreadsheet (from the spreadsheet gem) in order to build an XlS
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# @param [Hash] options A hash with options
|
11
11
|
# @return [Spreadsheet] A Spreadsheet object, ready for writing or more lower level operations
|
12
12
|
def to_html options={}
|
13
13
|
options = {:style_with_inline_css=>false}.merge(options)
|
14
|
-
builder = Nokogiri::
|
14
|
+
builder = Nokogiri::XML::Builder.new do |doc|
|
15
15
|
doc.html {
|
16
16
|
doc.body {
|
17
|
-
self.each{|sheet|
|
17
|
+
self.each{|sheet|
|
18
18
|
doc.h1 {
|
19
19
|
doc.text sheet.name
|
20
20
|
}
|
@@ -45,7 +45,7 @@ module Workbook
|
|
45
45
|
}
|
46
46
|
}
|
47
47
|
end
|
48
|
-
return builder.
|
48
|
+
return builder.doc.to_xhtml
|
49
49
|
end
|
50
50
|
|
51
51
|
|
@@ -53,11 +53,11 @@ module Workbook
|
|
53
53
|
# Write the current workbook to Microsoft Excel format (using the spreadsheet gem)
|
54
54
|
#
|
55
55
|
# @param [String] filename
|
56
|
-
# @param [Hash] options see #to_xls
|
56
|
+
# @param [Hash] options see #to_xls
|
57
57
|
def write_to_html filename="#{title}.html", options={}
|
58
58
|
File.open(filename, 'w') {|f| f.write(to_html(options)) }
|
59
59
|
return filename
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
63
|
-
end
|
63
|
+
end
|
@@ -6,7 +6,7 @@ module Workbook
|
|
6
6
|
module XlsWriter
|
7
7
|
|
8
8
|
# Generates an Spreadsheet (from the spreadsheet gem) in order to build an XlS
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# @param [Hash] options A hash with options (unused so far)
|
11
11
|
# @return [Spreadsheet] A Spreadsheet object, ready for writing or more lower level operations
|
12
12
|
def to_xls options={}
|
@@ -30,9 +30,9 @@ module Workbook
|
|
30
30
|
end
|
31
31
|
book
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Generates an Spreadsheet (from the spreadsheet gem) in order to build an XlS
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# @param [Workbook::Format, Hash] f A Workbook::Format or hash with format-options (:font_weight, :rotation, :background_color, :number_format, :text_direction, :color, :font_family)
|
37
37
|
# @return [Spreadsheet::Format] A Spreadsheet format-object, ready for writing or more lower level operations
|
38
38
|
def format_to_xls_format f
|
@@ -43,7 +43,7 @@ module Workbook
|
|
43
43
|
xlsfmt = f.return_raw_for Spreadsheet::Format
|
44
44
|
unless xlsfmt
|
45
45
|
xlsfmt=Spreadsheet::Format.new :weight=>f[:font_weight]
|
46
|
-
xlsfmt.rotation = f[:rotation] if f[:rotation]
|
46
|
+
xlsfmt.rotation = f[:rotation] if f[:rotation]
|
47
47
|
xlsfmt.pattern_fg_color = html_color_to_xls_color(f[:background_color]) if html_color_to_xls_color(f[:background_color])
|
48
48
|
xlsfmt.pattern = 1 if html_color_to_xls_color(f[:background_color])
|
49
49
|
xlsfmt.number_format = strftime_to_ms_format(f[:number_format]) if f[:number_format]
|
@@ -55,7 +55,7 @@ module Workbook
|
|
55
55
|
end
|
56
56
|
return xlsfmt
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# Attempt to convert html-hex color value to xls color number
|
60
60
|
#
|
61
61
|
# @param [String] hex color
|
@@ -66,26 +66,26 @@ module Workbook
|
|
66
66
|
end
|
67
67
|
return nil
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
# Converts standard (ruby/C++/unix/...) strftime formatting to MS's formatting
|
71
|
-
#
|
71
|
+
#
|
72
72
|
# @param [String, nil] numberformat (nil returns nil)
|
73
73
|
# @return [String, nil]
|
74
74
|
def strftime_to_ms_format numberformat
|
75
75
|
return nil if numberformat.nil?
|
76
76
|
return numberformat.gsub('%Y','yyyy').gsub('%A','dddd').gsub('%B','mmmm').gsub('%a','ddd').gsub('%b','mmm').gsub('%y','yy').gsub('%d','dd').gsub('%m','mm').gsub('%y','y').gsub('%y','%%y').gsub('%e','d')
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
# Write the current workbook to Microsoft Excel format (using the spreadsheet gem)
|
80
80
|
#
|
81
81
|
# @param [String] filename
|
82
|
-
# @param [Hash] options see #to_xls
|
82
|
+
# @param [Hash] options see #to_xls
|
83
83
|
def write_to_xls filename="#{title}.xls", options={}
|
84
84
|
if to_xls(options).write(filename)
|
85
85
|
return filename
|
86
86
|
end
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
def xls_sheet a
|
90
90
|
if xls_template.worksheet(a)
|
91
91
|
return xls_template.worksheet(a)
|
@@ -94,11 +94,11 @@ module Workbook
|
|
94
94
|
self.xls_sheet a
|
95
95
|
end
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
def xls_template
|
99
99
|
return template.raws[Spreadsheet::Excel::Workbook] ? template.raws[Spreadsheet::Excel::Workbook] : template.raws[Spreadsheet::Workbook]
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
def init_spreadsheet_template
|
103
103
|
if self.xls_template.is_a? Spreadsheet::Workbook
|
104
104
|
return self.xls_template
|
data/rbeautify.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
|
4
|
+
=begin
|
5
|
+
/***************************************************************************
|
6
|
+
* Copyright (C) 2008, Paul Lutus *
|
7
|
+
* *
|
8
|
+
* This program is free software; you can redistribute it and/or modify *
|
9
|
+
* it under the terms of the GNU General Public License as published by *
|
10
|
+
* the Free Software Foundation; either version 2 of the License, or *
|
11
|
+
* (at your option) any later version. *
|
12
|
+
* *
|
13
|
+
* This program is distributed in the hope that it will be useful, *
|
14
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
15
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
16
|
+
* GNU General Public License for more details. *
|
17
|
+
* *
|
18
|
+
* You should have received a copy of the GNU General Public License *
|
19
|
+
* along with this program; if not, write to the *
|
20
|
+
* Free Software Foundation, Inc., *
|
21
|
+
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
22
|
+
***************************************************************************/
|
23
|
+
=end
|
24
|
+
|
25
|
+
PVERSION = "Version 2.9, 10/24/2008"
|
26
|
+
|
27
|
+
module RBeautify
|
28
|
+
|
29
|
+
# user-customizable values
|
30
|
+
|
31
|
+
RBeautify::TabStr = " "
|
32
|
+
RBeautify::TabSize = 2
|
33
|
+
|
34
|
+
# indent regexp tests
|
35
|
+
|
36
|
+
IndentExp = [
|
37
|
+
/^module\b/,
|
38
|
+
/^class\b/,
|
39
|
+
/^if\b/,
|
40
|
+
/(=\s*|^)until\b/,
|
41
|
+
/(=\s*|^)for\b/,
|
42
|
+
/^unless\b/,
|
43
|
+
/(=\s*|^)while\b/,
|
44
|
+
/(=\s*|^)begin\b/,
|
45
|
+
/(^| )case\b/,
|
46
|
+
/\bthen\b/,
|
47
|
+
/^rescue\b/,
|
48
|
+
/^def\b/,
|
49
|
+
/\bdo\b/,
|
50
|
+
/^else\b/,
|
51
|
+
/^elsif\b/,
|
52
|
+
/^ensure\b/,
|
53
|
+
/\bwhen\b/,
|
54
|
+
/\{[^\}]*$/,
|
55
|
+
/\[[^\]]*$/
|
56
|
+
]
|
57
|
+
|
58
|
+
# outdent regexp tests
|
59
|
+
|
60
|
+
OutdentExp = [
|
61
|
+
/^rescue\b/,
|
62
|
+
/^ensure\b/,
|
63
|
+
/^elsif\b/,
|
64
|
+
/^end\b/,
|
65
|
+
/^else\b/,
|
66
|
+
/\bwhen\b/,
|
67
|
+
/^[^\{]*\}/,
|
68
|
+
/^[^\[]*\]/
|
69
|
+
]
|
70
|
+
|
71
|
+
def RBeautify.rb_make_tab(tab)
|
72
|
+
return (tab < 0)?"":TabStr * TabSize * tab
|
73
|
+
end
|
74
|
+
|
75
|
+
def RBeautify.rb_add_line(line,tab)
|
76
|
+
line.strip!
|
77
|
+
line = rb_make_tab(tab) + line if line.length > 0
|
78
|
+
return line
|
79
|
+
end
|
80
|
+
|
81
|
+
def RBeautify.beautify_string(source, path = "")
|
82
|
+
comment_block = false
|
83
|
+
in_here_doc = false
|
84
|
+
here_doc_term = ""
|
85
|
+
program_end = false
|
86
|
+
multiLine_array = []
|
87
|
+
multiLine_str = ""
|
88
|
+
tab = 0
|
89
|
+
output = []
|
90
|
+
source.each_line do |line|
|
91
|
+
line.chomp!
|
92
|
+
if(!program_end)
|
93
|
+
# detect program end mark
|
94
|
+
if(line =~ /^__END__$/)
|
95
|
+
program_end = true
|
96
|
+
else
|
97
|
+
# combine continuing lines
|
98
|
+
if(!(line =~ /^\s*#/) && line =~ /[^\\]\\\s*$/)
|
99
|
+
multiLine_array.push line
|
100
|
+
multiLine_str += line.sub(/^(.*)\\\s*$/,"\\1")
|
101
|
+
next
|
102
|
+
end
|
103
|
+
|
104
|
+
# add final line
|
105
|
+
if(multiLine_str.length > 0)
|
106
|
+
multiLine_array.push line
|
107
|
+
multiLine_str += line.sub(/^(.*)\\\s*$/,"\\1")
|
108
|
+
end
|
109
|
+
|
110
|
+
tline = ((multiLine_str.length > 0)?multiLine_str:line).strip
|
111
|
+
if(tline =~ /^=begin/)
|
112
|
+
comment_block = true
|
113
|
+
end
|
114
|
+
if(in_here_doc)
|
115
|
+
in_here_doc = false if tline =~ %r{\s*#{here_doc_term}\s*}
|
116
|
+
else # not in here_doc
|
117
|
+
if tline =~ %r{=\s*<<}
|
118
|
+
here_doc_term = tline.sub(%r{.*=\s*<<-?\s*([\w]+).*},"\\1")
|
119
|
+
in_here_doc = here_doc_term.size > 0
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
if(comment_block || program_end || in_here_doc)
|
125
|
+
# add the line unchanged
|
126
|
+
output << line
|
127
|
+
else
|
128
|
+
comment_line = (tline =~ /^#/)
|
129
|
+
if(!comment_line)
|
130
|
+
# throw out sequences that will
|
131
|
+
# only sow confusion
|
132
|
+
while tline.gsub!(/\{[^\{]*?\}/,"")
|
133
|
+
end
|
134
|
+
while tline.gsub!(/\[[^\[]*?\]/,"")
|
135
|
+
end
|
136
|
+
while tline.gsub!(/'.*?'/,"")
|
137
|
+
end
|
138
|
+
while tline.gsub!(/".*?"/,"")
|
139
|
+
end
|
140
|
+
while tline.gsub!(/\`.*?\`/,"")
|
141
|
+
end
|
142
|
+
while tline.gsub!(/\([^\(]*?\)/,"")
|
143
|
+
end
|
144
|
+
while tline.gsub!(/\/.*?\//,"")
|
145
|
+
end
|
146
|
+
while tline.gsub!(/%r(.).*?\1/,"")
|
147
|
+
end
|
148
|
+
# delete end-of-line comments
|
149
|
+
tline.sub!(/#[^\"]+$/,"")
|
150
|
+
# convert quotes
|
151
|
+
tline.gsub!(/\\\"/,"'")
|
152
|
+
OutdentExp.each do |re|
|
153
|
+
if(tline =~ re)
|
154
|
+
tab -= 1
|
155
|
+
break
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
if (multiLine_array.length > 0)
|
160
|
+
multiLine_array.each do |ml|
|
161
|
+
output << rb_add_line(ml,tab)
|
162
|
+
end
|
163
|
+
multiLine_array.clear
|
164
|
+
multiLine_str = ""
|
165
|
+
else
|
166
|
+
output << rb_add_line(line,tab)
|
167
|
+
end
|
168
|
+
if(!comment_line)
|
169
|
+
IndentExp.each do |re|
|
170
|
+
if(tline =~ re && !(tline =~ /\s+end\s*$/))
|
171
|
+
tab += 1
|
172
|
+
break
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
if(tline =~ /^=end/)
|
178
|
+
comment_block = false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
error = (tab != 0)
|
182
|
+
STDERR.puts "#{path}: Error: indent/outdent mismatch: #{tab}." if error
|
183
|
+
return output.join("\n") + "\n",error
|
184
|
+
end # beautify_string
|
185
|
+
|
186
|
+
def RBeautify.beautify_file(path, check)
|
187
|
+
error = false
|
188
|
+
if(path == '-') # stdin source
|
189
|
+
source = STDIN.read
|
190
|
+
dest,error = beautify_string(source,"stdin")
|
191
|
+
print dest
|
192
|
+
else # named file source
|
193
|
+
source = File.read(path)
|
194
|
+
dest,error = beautify_string(source,path)
|
195
|
+
if(source != dest && !error)
|
196
|
+
if check
|
197
|
+
puts "#{path} needs formatting"
|
198
|
+
error = "formatting"
|
199
|
+
else
|
200
|
+
# make a backup copy
|
201
|
+
File.open(path + "~","w") { |f| f.write(source) }
|
202
|
+
# overwrite the original
|
203
|
+
File.open(path,"w") { |f| f.write(dest) }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
return error
|
208
|
+
end # beautify_file
|
209
|
+
|
210
|
+
def RBeautify.main
|
211
|
+
error = false
|
212
|
+
check = false
|
213
|
+
if(!ARGV[0])
|
214
|
+
STDERR.puts "usage: Ruby filenames or \"-\" for stdin."
|
215
|
+
exit 0
|
216
|
+
end
|
217
|
+
if ARGV[0] == '--check'
|
218
|
+
check = true
|
219
|
+
ARGV.slice!(0)
|
220
|
+
end
|
221
|
+
ARGV.each do |argument|
|
222
|
+
error = (beautify_file(argument, check))?true:error
|
223
|
+
end
|
224
|
+
error = (error)?1:0
|
225
|
+
exit error
|
226
|
+
end # main
|
227
|
+
end # module RBeautify
|
228
|
+
|
229
|
+
# if launched as a standalone program, not loaded as a module
|
230
|
+
if __FILE__ == $0
|
231
|
+
RBeautify.main
|
232
|
+
end
|