workbook 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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