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.
Files changed (80) hide show
  1. data/.gitignore +2 -1
  2. data/.yardoc/checksums +22 -21
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/Gemfile.lock +2 -2
  6. data/doc/RubyXL.html +1 -1
  7. data/doc/RubyXL/Cell.html +1 -1
  8. data/doc/RubyXL/Workbook.html +31 -31
  9. data/doc/Workbook.html +4 -4
  10. data/doc/Workbook/Book.html +5 -5
  11. data/doc/Workbook/Cell.html +202 -62
  12. data/doc/Workbook/Format.html +32 -32
  13. data/doc/Workbook/Modules.html +1 -1
  14. data/doc/Workbook/Modules/RawObjectsStorage.html +5 -5
  15. data/doc/Workbook/Modules/TableDiffSort.html +14 -14
  16. data/doc/Workbook/Modules/TypeParser.html +7 -7
  17. data/doc/Workbook/NilValue.html +434 -0
  18. data/doc/Workbook/Readers.html +3 -3
  19. data/doc/Workbook/Readers/CsvReader.html +6 -6
  20. data/doc/Workbook/Readers/OdsReader.html +562 -60
  21. data/doc/Workbook/Readers/TxtReader.html +2 -2
  22. data/doc/Workbook/Readers/XlsReader.html +14 -14
  23. data/doc/Workbook/Readers/XlsShared.html +67 -67
  24. data/doc/Workbook/Readers/XlsxReader.html +7 -7
  25. data/doc/Workbook/Row.html +243 -5
  26. data/doc/Workbook/Sheet.html +2 -2
  27. data/doc/Workbook/Table.html +669 -58
  28. data/doc/Workbook/Template.html +5 -5
  29. data/doc/Workbook/Writers.html +1 -1
  30. data/doc/Workbook/Writers/CsvTableWriter.html +1 -1
  31. data/doc/Workbook/Writers/HtmlWriter.html +27 -13
  32. data/doc/Workbook/Writers/XlsWriter.html +2 -2
  33. data/doc/_index.html +23 -8
  34. data/doc/class_list.html +1 -1
  35. data/doc/file.README.html +16 -12
  36. data/doc/index.html +16 -12
  37. data/doc/method_list.html +232 -72
  38. data/doc/top-level-namespace.html +1 -1
  39. data/lib/workbook/book.rb +25 -25
  40. data/lib/workbook/cell.rb +33 -33
  41. data/lib/workbook/format.rb +10 -10
  42. data/lib/workbook/modules/raw_objects_storage.rb +19 -19
  43. data/lib/workbook/modules/table_diff_sort.rb +22 -22
  44. data/lib/workbook/modules/type_parser.rb +18 -18
  45. data/lib/workbook/nil_value.rb +6 -6
  46. data/lib/workbook/readers/csv_reader.rb +8 -8
  47. data/lib/workbook/readers/ods_reader.rb +92 -46
  48. data/lib/workbook/readers/txt_reader.rb +2 -2
  49. data/lib/workbook/readers/xls_reader.rb +19 -19
  50. data/lib/workbook/readers/xls_shared.rb +70 -70
  51. data/lib/workbook/readers/xlsx_reader.rb +42 -42
  52. data/lib/workbook/row.rb +59 -29
  53. data/lib/workbook/sheet.rb +8 -8
  54. data/lib/workbook/table.rb +52 -19
  55. data/lib/workbook/template.rb +10 -10
  56. data/lib/workbook/version.rb +1 -1
  57. data/lib/workbook/writers/csv_table_writer.rb +1 -1
  58. data/lib/workbook/writers/html_writer.rb +6 -6
  59. data/lib/workbook/writers/xls_writer.rb +12 -12
  60. data/rbeautify.rb +232 -0
  61. data/test/artifacts/book_with_colspans.ods +0 -0
  62. data/test/artifacts/book_with_tabs_and_colours.ods +0 -0
  63. data/test/test_book.rb +10 -10
  64. data/test/test_cell.rb +14 -14
  65. data/test/test_format.rb +11 -11
  66. data/test/test_functional.rb +3 -3
  67. data/test/test_modules_table_diff_sort.rb +24 -24
  68. data/test/test_modules_type_parser.rb +27 -27
  69. data/test/test_readers_csv_reader.rb +11 -11
  70. data/test/test_readers_ods_reader.rb +22 -15
  71. data/test/test_readers_txt_reader.rb +13 -13
  72. data/test/test_readers_xls_reader.rb +11 -11
  73. data/test/test_readers_xlsx_reader.rb +5 -5
  74. data/test/test_row.rb +96 -26
  75. data/test/test_sheet.rb +9 -9
  76. data/test/test_table.rb +42 -26
  77. data/test/test_template.rb +3 -3
  78. data/test/test_writers_html_writer.rb +6 -4
  79. data/test/test_writers_xls_writer.rb +7 -7
  80. metadata +5 -1
@@ -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
@@ -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
@@ -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
- end
53
+ end
54
54
  end
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module Workbook
3
- VERSION = '0.4.2'
3
+ VERSION = '0.4.3'
4
4
  end
@@ -18,7 +18,7 @@ module Workbook
18
18
  end
19
19
  csv
20
20
  end
21
-
21
+
22
22
  end
23
23
  end
24
24
  end
@@ -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::HTML::Builder.new do |doc|
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.to_html
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