keeguon-spreadsheet 0.9.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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +619 -0
  3. data/Manifest.txt +85 -0
  4. data/bin/xlsopcodes +18 -0
  5. data/lib/parseexcel.rb +27 -0
  6. data/lib/parseexcel/parseexcel.rb +75 -0
  7. data/lib/parseexcel/parser.rb +11 -0
  8. data/lib/spreadsheet.rb +80 -0
  9. data/lib/spreadsheet/column.rb +71 -0
  10. data/lib/spreadsheet/compatibility.rb +23 -0
  11. data/lib/spreadsheet/datatypes.rb +161 -0
  12. data/lib/spreadsheet/encodings.rb +57 -0
  13. data/lib/spreadsheet/excel.rb +88 -0
  14. data/lib/spreadsheet/excel/error.rb +26 -0
  15. data/lib/spreadsheet/excel/internals.rb +458 -0
  16. data/lib/spreadsheet/excel/internals/biff5.rb +17 -0
  17. data/lib/spreadsheet/excel/internals/biff8.rb +19 -0
  18. data/lib/spreadsheet/excel/offset.rb +41 -0
  19. data/lib/spreadsheet/excel/password_hash.rb +24 -0
  20. data/lib/spreadsheet/excel/reader.rb +1302 -0
  21. data/lib/spreadsheet/excel/reader/biff5.rb +42 -0
  22. data/lib/spreadsheet/excel/reader/biff8.rb +231 -0
  23. data/lib/spreadsheet/excel/rgb.rb +122 -0
  24. data/lib/spreadsheet/excel/row.rb +98 -0
  25. data/lib/spreadsheet/excel/sst_entry.rb +46 -0
  26. data/lib/spreadsheet/excel/workbook.rb +80 -0
  27. data/lib/spreadsheet/excel/worksheet.rb +115 -0
  28. data/lib/spreadsheet/excel/writer.rb +1 -0
  29. data/lib/spreadsheet/excel/writer/biff8.rb +75 -0
  30. data/lib/spreadsheet/excel/writer/format.rb +264 -0
  31. data/lib/spreadsheet/excel/writer/n_worksheet.rb +888 -0
  32. data/lib/spreadsheet/excel/writer/workbook.rb +735 -0
  33. data/lib/spreadsheet/excel/writer/worksheet.rb +940 -0
  34. data/lib/spreadsheet/font.rb +115 -0
  35. data/lib/spreadsheet/format.rb +209 -0
  36. data/lib/spreadsheet/formula.rb +9 -0
  37. data/lib/spreadsheet/helpers.rb +11 -0
  38. data/lib/spreadsheet/link.rb +43 -0
  39. data/lib/spreadsheet/note.rb +23 -0
  40. data/lib/spreadsheet/noteObject.rb +17 -0
  41. data/lib/spreadsheet/row.rb +151 -0
  42. data/lib/spreadsheet/workbook.rb +143 -0
  43. data/lib/spreadsheet/worksheet.rb +326 -0
  44. data/lib/spreadsheet/writer.rb +30 -0
  45. data/test/data/test_adding_data_to_existing_file.xls +0 -0
  46. data/test/data/test_borders.xls +0 -0
  47. data/test/data/test_changes.xls +0 -0
  48. data/test/data/test_comment.xls +0 -0
  49. data/test/data/test_copy.xls +0 -0
  50. data/test/data/test_datetime.xls +0 -0
  51. data/test/data/test_empty.xls +0 -0
  52. data/test/data/test_formula.xls +0 -0
  53. data/test/data/test_long_sst_record.xls +0 -0
  54. data/test/data/test_margin.xls +0 -0
  55. data/test/data/test_merged_and_protected.xls +0 -0
  56. data/test/data/test_merged_cells.xls +0 -0
  57. data/test/data/test_missing_row.xls +0 -0
  58. data/test/data/test_pagesetup.xls +0 -0
  59. data/test/data/test_version_excel5.xls +0 -0
  60. data/test/data/test_version_excel95.xls +0 -0
  61. data/test/data/test_version_excel97.xls +0 -0
  62. data/test/data/test_version_excel97_2010.xls +0 -0
  63. data/test/data/test_worksheet_visibility.xls +0 -0
  64. data/test/excel/reader.rb +30 -0
  65. data/test/excel/row.rb +40 -0
  66. data/test/excel/writer/workbook.rb +95 -0
  67. data/test/excel/writer/worksheet.rb +81 -0
  68. data/test/font.rb +163 -0
  69. data/test/format.rb +95 -0
  70. data/test/integration.rb +1390 -0
  71. data/test/row.rb +33 -0
  72. data/test/suite.rb +18 -0
  73. data/test/workbook.rb +55 -0
  74. data/test/workbook_protection.rb +19 -0
  75. data/test/worksheet.rb +112 -0
  76. metadata +148 -0
@@ -0,0 +1,85 @@
1
+ .gitignore
2
+ .travis.yml
3
+ GUIDE.md
4
+ Gemfile
5
+ Gemfile.lock
6
+ History.md
7
+ LICENSE.txt
8
+ Manifest.txt
9
+ README.md
10
+ Rakefile
11
+ bin/xlsopcodes
12
+ doc/Excel97-2007BinaryFileFormatSpecification.pdf
13
+ doc/excelfileformat.pdf
14
+ lib/parseexcel.rb
15
+ lib/parseexcel/parseexcel.rb
16
+ lib/parseexcel/parser.rb
17
+ lib/spreadsheet.rb
18
+ lib/spreadsheet/column.rb
19
+ lib/spreadsheet/compatibility.rb
20
+ lib/spreadsheet/datatypes.rb
21
+ lib/spreadsheet/encodings.rb
22
+ lib/spreadsheet/excel.rb
23
+ lib/spreadsheet/excel/error.rb
24
+ lib/spreadsheet/excel/internals.rb
25
+ lib/spreadsheet/excel/internals/biff5.rb
26
+ lib/spreadsheet/excel/internals/biff8.rb
27
+ lib/spreadsheet/excel/offset.rb
28
+ lib/spreadsheet/excel/password_hash.rb
29
+ lib/spreadsheet/excel/reader.rb
30
+ lib/spreadsheet/excel/reader/biff5.rb
31
+ lib/spreadsheet/excel/reader/biff8.rb
32
+ lib/spreadsheet/excel/rgb.rb
33
+ lib/spreadsheet/excel/row.rb
34
+ lib/spreadsheet/excel/sst_entry.rb
35
+ lib/spreadsheet/excel/workbook.rb
36
+ lib/spreadsheet/excel/worksheet.rb
37
+ lib/spreadsheet/excel/writer.rb
38
+ lib/spreadsheet/excel/writer/biff8.rb
39
+ lib/spreadsheet/excel/writer/format.rb
40
+ lib/spreadsheet/excel/writer/n_worksheet.rb
41
+ lib/spreadsheet/excel/writer/workbook.rb
42
+ lib/spreadsheet/excel/writer/worksheet.rb
43
+ lib/spreadsheet/font.rb
44
+ lib/spreadsheet/format.rb
45
+ lib/spreadsheet/formula.rb
46
+ lib/spreadsheet/helpers.rb
47
+ lib/spreadsheet/link.rb
48
+ lib/spreadsheet/note.rb
49
+ lib/spreadsheet/noteObject.rb
50
+ lib/spreadsheet/row.rb
51
+ lib/spreadsheet/workbook.rb
52
+ lib/spreadsheet/worksheet.rb
53
+ lib/spreadsheet/writer.rb
54
+ spreadsheet.gemspec
55
+ test/data/test_adding_data_to_existing_file.xls
56
+ test/data/test_borders.xls
57
+ test/data/test_changes.xls
58
+ test/data/test_comment.xls
59
+ test/data/test_copy.xls
60
+ test/data/test_datetime.xls
61
+ test/data/test_empty.xls
62
+ test/data/test_formula.xls
63
+ test/data/test_long_sst_record.xls
64
+ test/data/test_margin.xls
65
+ test/data/test_merged_and_protected.xls
66
+ test/data/test_merged_cells.xls
67
+ test/data/test_missing_row.xls
68
+ test/data/test_pagesetup.xls
69
+ test/data/test_version_excel5.xls
70
+ test/data/test_version_excel95.xls
71
+ test/data/test_version_excel97.xls
72
+ test/data/test_version_excel97_2010.xls
73
+ test/data/test_worksheet_visibility.xls
74
+ test/excel/reader.rb
75
+ test/excel/row.rb
76
+ test/excel/writer/workbook.rb
77
+ test/excel/writer/worksheet.rb
78
+ test/font.rb
79
+ test/format.rb
80
+ test/integration.rb
81
+ test/row.rb
82
+ test/suite.rb
83
+ test/workbook.rb
84
+ test/workbook_protection.rb
85
+ test/worksheet.rb
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'spreadsheet'
4
+
5
+ source, target = ARGV
6
+
7
+ if source.nil?
8
+ puts "Usage: #{$0} <source> [<target>]"
9
+ exit -1
10
+ end
11
+
12
+ target = target ? File.open(target, 'w') : STDOUT
13
+
14
+ reader = Spreadsheet::Excel::Reader.new :print_opcodes => target
15
+ reader.setup File.open(source)
16
+
17
+ while tuple = reader.get_next_chunk
18
+ end
@@ -0,0 +1,27 @@
1
+ ### Spreadsheet - A Library for reading and writing Spreadsheet Documents.
2
+ #
3
+ # Copyright (C) 2008 Hannes Wyss
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ # Contact Information:
19
+ #
20
+ # E-Mail: hannes.wyss@gmail.com
21
+ # P-Mail: ywesee GmbH
22
+ # Hannes Wyss
23
+ # Winterthurerstrasse 52
24
+ # 8006 Zürich
25
+ ### Switzerland
26
+
27
+ require 'parseexcel/parseexcel'
@@ -0,0 +1,75 @@
1
+ require 'spreadsheet'
2
+
3
+ warn <<-EOS
4
+ [DEPRECATED] By requiring 'parseexcel', 'parseexcel/parseexcel' and/or
5
+ 'parseexcel/parser' you are loading a Compatibility layer which
6
+ provides a drop-in replacement for the ParseExcel library. This
7
+ code makes the reading of Spreadsheet documents less efficient and
8
+ will be removed in Spreadsheet version 1.0.0
9
+ EOS
10
+
11
+ module Spreadsheet
12
+ ##
13
+ # The ParseExcel module is provided as a drop-in replacement for the
14
+ # ParseExcel library. This code is deprecated and will be removed in
15
+ # Spreadsheet version 1.0.0
16
+ module ParseExcel
17
+ def ParseExcel.parse path
18
+ Spreadsheet.open path
19
+ end
20
+ class Worksheet
21
+ class Cell
22
+ attr_accessor :value, :kind, :numeric, :code, :book,
23
+ :format, :rich, :encoding, :annotation
24
+ def initialize value, format, row, idx
25
+ @format = format
26
+ @idx = idx
27
+ @row = row
28
+ @value = value
29
+ @encoding = Spreadsheet.client_encoding
30
+ end
31
+ def date
32
+ @row.date @idx
33
+ end
34
+ def datetime
35
+ @row.datetime @idx
36
+ end
37
+ def to_i
38
+ @value.to_i
39
+ end
40
+ def to_f
41
+ @value.to_f
42
+ end
43
+ def to_s(target_encoding=nil)
44
+ if(target_encoding)
45
+ begin
46
+ Iconv.new(target_encoding, @encoding).iconv(@value)
47
+ rescue
48
+ Iconv.new(target_encoding, 'ascii').iconv(@value.to_s)
49
+ end
50
+ else
51
+ @value.to_s
52
+ end
53
+ end
54
+ def type
55
+ if @format && (@format.date? || @format.time?)
56
+ :date
57
+ elsif @value.is_a?(Numeric)
58
+ :numeric
59
+ else
60
+ :text
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ module Excel
67
+ class Reader # :nodoc: all
68
+ def set_cell worksheet, row, column, xf, value=nil
69
+ cells = @current_row_block[row] ||= Row.new(nil, row)
70
+ cells.formats[column] = xf = @workbook.format(xf)
71
+ cells[column] = ParseExcel::Worksheet::Cell.new(value, xf, cells, column)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,11 @@
1
+ require 'parseexcel'
2
+
3
+ module Spreadsheet
4
+ module ParseExcel # :nodoc: all
5
+ class Parser
6
+ def parse path
7
+ Spreadsheet.open path
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,80 @@
1
+ ### Spreadsheet - A Library for reading and writing Spreadsheet Documents.
2
+ #
3
+ # Copyright (C) 2008-2010 ywesee GmbH
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ # Contact Information:
19
+ #
20
+ # E-Mail: mhatakeyama@ywesee.com, zdavatz@ywesee.com
21
+ # P-Mail: ywesee GmbH
22
+ # Zeno R.R. Davatz
23
+ # Winterthurerstrasse 52
24
+ # 8006 Zürich
25
+ ### Switzerland
26
+
27
+ require 'spreadsheet/excel/workbook'
28
+ require 'spreadsheet/excel/reader'
29
+ require 'spreadsheet/excel/rgb'
30
+
31
+ # = Synopsis
32
+ # The Spreadsheet Library is designed to read and write Spreadsheet Documents.
33
+ # As of version 0.6.0, only Microsoft Excel compatible spreadsheets are
34
+ # supported.
35
+ #
36
+ # == Example
37
+ # require 'spreadsheet'
38
+ #
39
+ # book = Spreadsheet.open '/path/to/an/excel-file.xls'
40
+ # sheet = book.worksheet 0
41
+ # sheet.each do |row| puts row[0] end
42
+ module Spreadsheet
43
+
44
+ ##
45
+ # The version of Spreadsheet you are using.
46
+ VERSION = '0.9.4'
47
+
48
+ ##
49
+ # Default client Encoding. Change this value if your application uses a
50
+ # different Encoding:
51
+ # Spreadsheet.client_encoding = 'ISO-LATIN-1//TRANSLIT//IGNORE'
52
+ @client_encoding = 'UTF-8'
53
+
54
+ class << self
55
+
56
+ attr_accessor :client_encoding
57
+
58
+ ##
59
+ # Parses a Spreadsheet Document and returns a Workbook object. At present,
60
+ # only Excel-Documents can be read.
61
+ def open io_or_path, mode="rb+"
62
+ if io_or_path.respond_to? :seek
63
+ Excel::Workbook.open(io_or_path)
64
+ elsif block_given?
65
+ File.open(io_or_path, mode) do |fh|
66
+ yield open(fh)
67
+ end
68
+ else
69
+ open File.open(io_or_path, mode)
70
+ end
71
+ end
72
+
73
+ ##
74
+ # Returns a Writer object for the specified path. At present, only the
75
+ # Excel-Writer is available.
76
+ def writer io_or_path, type=Excel
77
+ Excel::Writer::Workbook.new io_or_path
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,71 @@
1
+ require 'spreadsheet/datatypes'
2
+
3
+ module Spreadsheet
4
+ ##
5
+ # The Column class. Encapsulates column-formatting and width, and provides a
6
+ # means to iterate over all cells in a column.
7
+ #
8
+ # Useful Attributes:
9
+ # #width:: The width in characters (in respect to the '0' character
10
+ # of the Worksheet's default Font). Float values are
11
+ # permitted, for Excel the available Precision is at 1/256
12
+ # characters.
13
+ # #default_format:: The default Format for cells in this column (applied if
14
+ # there is no explicit Cell Format and no default Row format
15
+ # for the Cell).
16
+ # #hidden:: The Column is hidden.
17
+ # #collapsed:: The Column is collapsed.
18
+ # #outline_level:: Outline level of the column.
19
+ class Column
20
+ class << self
21
+ def updater *keys
22
+ keys.each do |key|
23
+ unless instance_methods.include? "unupdated_#{key}="
24
+ alias_method :"unupdated_#{key}=", :"#{key}="
25
+ define_method "#{key}=" do |value|
26
+ send "unupdated_#{key}=", value
27
+ @worksheet.column_updated @idx, self if @worksheet
28
+ value
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ include Datatypes
35
+ include Enumerable
36
+ attr_accessor :width, :worksheet
37
+ attr_reader :default_format, :idx
38
+ boolean :hidden, :collapsed
39
+ enum :outline_level, 0, Integer
40
+ updater :collapsed, :hidden, :outline_level, :width
41
+ def initialize idx, format, opts={}
42
+ @worksheet = nil
43
+ @idx = idx
44
+ opts[:width] ||= 10
45
+ opts.each do |key, value|
46
+ self.send "#{key}=", value
47
+ end
48
+ self.default_format = format
49
+ end
50
+ ##
51
+ # Set the default Format for Cells in this Column.
52
+ def default_format= format
53
+ @worksheet.add_format format if @worksheet
54
+ @default_format = format
55
+ @worksheet.column_updated @idx, self if @worksheet
56
+ format
57
+ end
58
+ ##
59
+ # Iterate over all cells in this column.
60
+ def each
61
+ @worksheet.each do |row|
62
+ yield row[idx]
63
+ end
64
+ end
65
+ def == other # :nodoc:
66
+ other.is_a?(Column) && default_format == other.default_format \
67
+ && width == other.width && hidden == other.hidden \
68
+ && collapsed == other.collapsed && outline_level == other.outline_level
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,23 @@
1
+ module Spreadsheet
2
+ module Compatibility
3
+ ##
4
+ # One of the most incisive changes in terms of meta-programming in Ruby 1.9
5
+ # is the switch from representing instance-variable names as Strings to
6
+ # presenting them as Symbols. ivar_name provides compatibility.
7
+ if RUBY_VERSION >= '1.9'
8
+ def ivar_name symbol
9
+ :"@#{symbol}"
10
+ end
11
+ def method_name symbol
12
+ symbol.to_sym
13
+ end
14
+ else
15
+ def ivar_name symbol
16
+ "@#{symbol}"
17
+ end
18
+ def method_name symbol
19
+ symbol.to_s
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,161 @@
1
+ require 'spreadsheet/compatibility'
2
+
3
+ module Spreadsheet
4
+ ##
5
+ # This module defines convenience-methods for the definition of Spreadsheet
6
+ # attributes (boolean, colors and enumerations)
7
+ module Datatypes
8
+ include Compatibility
9
+ def Datatypes.append_features mod
10
+ super
11
+ mod.module_eval do
12
+ class << self
13
+ ##
14
+ # Valid colors for color attributes.
15
+ COLORS = [ :builtin_black, :builtin_white, :builtin_red, :builtin_green,
16
+ :builtin_blue, :builtin_yellow, :builtin_magenta, :builtin_cyan,
17
+ :text, :border, :pattern_bg, :dialog_bg, :chart_text, :chart_bg,
18
+ :chart_border, :tooltip_bg, :tooltip_text, :aqua,
19
+ :black, :blue, :cyan, :brown, :fuchsia, :gray, :grey, :green,
20
+ :lime, :magenta, :navy, :orange, :purple, :red, :silver, :white,
21
+ :yellow,
22
+ :xls_color_0,
23
+ :xls_color_1,
24
+ :xls_color_2,
25
+ :xls_color_3,
26
+ :xls_color_4,
27
+ :xls_color_5,
28
+ :xls_color_6,
29
+ :xls_color_7,
30
+ :xls_color_8,
31
+ :xls_color_9,
32
+ :xls_color_10,
33
+ :xls_color_11,
34
+ :xls_color_12,
35
+ :xls_color_13,
36
+ :xls_color_14,
37
+ :xls_color_15,
38
+ :xls_color_16,
39
+ :xls_color_17,
40
+ :xls_color_18,
41
+ :xls_color_19,
42
+ :xls_color_20,
43
+ :xls_color_21,
44
+ :xls_color_22,
45
+ :xls_color_23,
46
+ :xls_color_24,
47
+ :xls_color_25,
48
+ :xls_color_26,
49
+ :xls_color_27,
50
+ :xls_color_28,
51
+ :xls_color_29,
52
+ :xls_color_30,
53
+ :xls_color_31,
54
+ :xls_color_32,
55
+ :xls_color_33,
56
+ :xls_color_34,
57
+ :xls_color_35,
58
+ :xls_color_36,
59
+ :xls_color_37,
60
+ :xls_color_38,
61
+ :xls_color_39,
62
+ :xls_color_40,
63
+ :xls_color_41,
64
+ :xls_color_42,
65
+ :xls_color_43,
66
+ :xls_color_44,
67
+ :xls_color_45,
68
+ :xls_color_46,
69
+ :xls_color_47,
70
+ :xls_color_48,
71
+ :xls_color_49,
72
+ :xls_color_50,
73
+ :xls_color_51,
74
+ :xls_color_52,
75
+ :xls_color_53,
76
+ :xls_color_54,
77
+ :xls_color_55 ]
78
+ ##
79
+ # Define instance methods to read and write boolean attributes.
80
+ def boolean *args
81
+ args.each do |key|
82
+ define_method key do
83
+ name = ivar_name key
84
+ !!(instance_variable_get(name) if instance_variables.include?(name))
85
+ end
86
+ define_method "#{key}?" do
87
+ send key
88
+ end
89
+ define_method "#{key}=" do |arg|
90
+ arg = false if arg == 0
91
+ instance_variable_set(ivar_name(key), !!arg)
92
+ end
93
+ define_method "#{key}!" do
94
+ send "#{key}=", true
95
+ end
96
+ end
97
+ end
98
+ ##
99
+ # Define instance methods to read and write color attributes.
100
+ # For valid colors see COLORS
101
+ def colors *args
102
+ args.each do |key|
103
+ attr_reader key
104
+ define_method "#{key}=" do |name|
105
+ name = name.to_s.downcase.to_sym
106
+ if COLORS.include?(name)
107
+ instance_variable_set ivar_name(key), name
108
+ else
109
+ raise ArgumentError, "unknown color '#{name}'"
110
+ end
111
+ end
112
+ end
113
+ end
114
+ ##
115
+ # Define instance methods to read and write enumeration attributes.
116
+ # * The first argument designates the attribute name.
117
+ # * The second argument designates the default value.
118
+ # * All subsequent attributes are possible values.
119
+ # * If the last attribute is a Hash, each value in the Hash designates
120
+ # aliases for the corresponding key.
121
+ def enum key, *values
122
+ aliases = {}
123
+ if values.last.is_a? Hash
124
+ values.pop.each do |value, synonyms|
125
+ if synonyms.is_a? Array
126
+ synonyms.each do |synonym| aliases.store synonym, value end
127
+ else
128
+ aliases.store synonyms, value
129
+ end
130
+ end
131
+ end
132
+ values.each do |value|
133
+ aliases.store value, value
134
+ end
135
+ define_method key do
136
+ name = ivar_name key
137
+ value = instance_variable_get(name) if instance_variables.include? name
138
+ value || values.first
139
+ end
140
+ define_method "#{key}=" do |arg|
141
+ if arg
142
+ arg = aliases.fetch arg do
143
+ aliases.fetch arg.to_s.downcase.gsub(/[ \-]/, '_').to_sym, arg
144
+ end
145
+ if values.any? do |val| val === arg end
146
+ instance_variable_set(ivar_name(key), arg)
147
+ else
148
+ valid = values.collect do |val| val.inspect end.join ', '
149
+ raise ArgumentError,
150
+ "Invalid value '#{arg.inspect}' for #{key}. Valid values are: #{valid}"
151
+ end
152
+ else
153
+ instance_variable_set ivar_name(key), values.first
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end