xmlss 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +28 -0
  4. data/README.rdoc +154 -0
  5. data/Rakefile +7 -0
  6. data/examples/example_workbook.rb +19 -0
  7. data/examples/layout.rb +81 -0
  8. data/examples/simple.rb +30 -0
  9. data/examples/styles.rb +85 -0
  10. data/examples/text.rb +36 -0
  11. data/lib/xmlss/cell.rb +38 -0
  12. data/lib/xmlss/column.rb +28 -0
  13. data/lib/xmlss/data.rb +67 -0
  14. data/lib/xmlss/enum.rb +56 -0
  15. data/lib/xmlss/item_set.rb +17 -0
  16. data/lib/xmlss/row.rb +34 -0
  17. data/lib/xmlss/style/alignment.rb +47 -0
  18. data/lib/xmlss/style/base.rb +63 -0
  19. data/lib/xmlss/style/border.rb +43 -0
  20. data/lib/xmlss/style/font.rb +41 -0
  21. data/lib/xmlss/style/interior.rb +41 -0
  22. data/lib/xmlss/style/number_format.rb +20 -0
  23. data/lib/xmlss/style/protection.rb +18 -0
  24. data/lib/xmlss/table.rb +22 -0
  25. data/lib/xmlss/version.rb +3 -0
  26. data/lib/xmlss/workbook.rb +33 -0
  27. data/lib/xmlss/worksheet.rb +37 -0
  28. data/lib/xmlss/xml.rb +55 -0
  29. data/lib/xmlss.rb +31 -0
  30. data/test/cell_test.rb +86 -0
  31. data/test/column_test.rb +46 -0
  32. data/test/data_test.rb +75 -0
  33. data/test/enum_test.rb +63 -0
  34. data/test/env.rb +10 -0
  35. data/test/helper.rb +49 -0
  36. data/test/item_set_test.rb +26 -0
  37. data/test/row_test.rb +67 -0
  38. data/test/style/alignment_test.rb +107 -0
  39. data/test/style/base_test.rb +126 -0
  40. data/test/style/border_test.rb +114 -0
  41. data/test/style/font_test.rb +100 -0
  42. data/test/style/interior_test.rb +87 -0
  43. data/test/style/number_format_test.rb +50 -0
  44. data/test/style/protection_test.rb +45 -0
  45. data/test/table_test.rb +53 -0
  46. data/test/thing.rb +5 -0
  47. data/test/workbook_test.rb +59 -0
  48. data/test/worksheet_test.rb +62 -0
  49. data/test/xml_test.rb +61 -0
  50. data/test/xmlss_test.rb +29 -0
  51. data/xmlss.gemspec +23 -0
  52. metadata +184 -0
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ pkg/*
2
+ .bundle
3
+ *.gem
4
+ *.log
5
+ *.xml
6
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in xmlss.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ xmlss (0.0.1)
5
+ nokogiri (~> 1.4.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ json (1.5.1)
11
+ kelredd-useful (0.4.1)
12
+ json
13
+ leftright (0.9.0)
14
+ nokogiri (1.4.4)
15
+ shoulda (2.11.3)
16
+ test-belt (0.2.1)
17
+ kelredd-useful (~> 0.4.0)
18
+ leftright (~> 0.9.0)
19
+ shoulda (~> 2.11)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bundler (~> 1.0)
26
+ nokogiri (~> 1.4.0)
27
+ test-belt (= 0.2.1)
28
+ xmlss!
data/README.rdoc ADDED
@@ -0,0 +1,154 @@
1
+ = Xmlss
2
+
3
+ == Description
4
+
5
+ This gem allows you to generate spreadsheets in the XML Spreadsheet format. It provides an api for constructing spreadsheet data and then uses that data to generate xml that can be interpreted by MS Excel.
6
+
7
+ ** Note: this gem only generates XML according to a subset of the August 2001 XML Spreadsheet spec (http://msdn.microsoft.com/en-us/library/aa140066(office.10).aspx). It does not generate the more modern open office spreadsheet spec (xlsx).
8
+
9
+ == Installation
10
+
11
+ gem install xmlss
12
+
13
+ == Simple Example
14
+
15
+ require 'xmlss'
16
+
17
+ workbook = Xmlss::Workbook.new
18
+ workbook.worksheets # => []
19
+
20
+ sheet1 = Xmlss::Worksheet.new({
21
+ :name => 'Sheet 1'
22
+ })
23
+ sheet1.table = Xmlss::Table.new
24
+ sheet1.table.rows # => []
25
+
26
+ row1 = Xmlss::Row.new(1, 'some data', 54.54)
27
+ row1.cells.count = 3
28
+ row1.cells.first.data # => 1
29
+
30
+ sheet1.table.rows << row1
31
+ workbook.worksheets << sheet1
32
+
33
+ workbook.to_xml # => "..." (XML Spreadsheet xml string)
34
+
35
+ == Usage
36
+ see the examples folder for some use case examples.
37
+
38
+ Be aware this library only provides the basic, raw API for constructing spreadsheets using this spec and utilities to convert those objects to string xml data representing them. It does not provide any macro logic to aid in constructing the sheets. If you want a more convenient API for your use case, I suggest subclassing the objects and tailoring them to your needs.
39
+
40
+ The XML Spreadsheet spec and format are legacy and may have limited support depending on your version of MS Excel. For a more modern spreadsheet generation method, I suggest looking into Office Open XML Workbook format (http://en.wikipedia.org/wiki/Office_Open_XML).
41
+
42
+ == API
43
+
44
+ These classes define how a spreadsheet is constructed.
45
+ === Xmlss::Workbook
46
+ * *styles*: array, Xmlss:Style objects, default: []
47
+ * *worksheets*: array, Xmlss::Worksheet objects, default: []
48
+
49
+ === Xmlss::Worksheet
50
+ * *name*: string
51
+ * *table*: Xmlss::Table object
52
+
53
+ === Xmlss::Table
54
+ * *columns*: array, Xmlss::Column objects, default: []
55
+ * *rows*: array, Xmlss::Row objects, default: []
56
+
57
+ === Xmlss::Column
58
+ * *style_id*: string
59
+ * *width*: numeric
60
+ * *auto_fit_width*: bool, default: false
61
+ * *hidden*: bool, default: false
62
+
63
+ === Xmlss::Row
64
+ * *style_id*: string
65
+ * *height*: numeric
66
+ * *auto_fit_height*: bool, default: false
67
+ * *hidden*: bool, default: false
68
+ * *cells*: array, Xmlss::Cell objects, default: []
69
+
70
+ === Xmlss::Cell
71
+ * *style_id*: string
72
+ * *data*: Xmlss::Data object
73
+ * *formula*: string
74
+ * *href*: string
75
+ * *merge_across*: int, default: 0
76
+ * *merge_down*: int, default: 0
77
+ * *tool_tip*: string
78
+
79
+ === Xmlss::Data
80
+ * *type*: :number, :datetime, :boolean, :string, :error, required
81
+ * *value*: needs to respond to 'to_s'
82
+
83
+
84
+ These classes define how a spreadsheet cells are styled.
85
+ === Xmlss::Style
86
+ * *id*: string, unique identifier for the style
87
+ * *alignment*: Xmlss::Style::Alignment object
88
+ * *borders*: array, Xmlss::Style::Border objects, default: []
89
+ * *font*: Xmlss::Style::Font object
90
+ * *interior*: Xmlss::Style::Interior object
91
+ * *number_format*: Xmlss::Style::NumberFormat object
92
+ * *protection*: Xmlss::Protection object
93
+
94
+ === Xmlss::Style::Alignment
95
+ * *horizontal*: :automatic, :left, :center, :right, :default, default: :default
96
+ * *vertical*: :automatic, :top, :center, :bottom, :default, default: :default
97
+ * *wrap_text*: bool, default: false
98
+ * *rotate*: int (-90 to 90)
99
+
100
+ === Xmlss::Style::Border
101
+ * *position*: :left, :top, :right, :bottom
102
+ * *color*: hex string
103
+ * *style*: :none, :continuous, :dash, :dot, :dash_dot, :dash_dot_dot, default: :continuous
104
+ * *weight*: :hairline, :thin, :medium, :thick, default: :thin
105
+
106
+ === Xmlss::Style::Font
107
+ * *bold*: bool, default: false
108
+ * *color*: hex string
109
+ * *name*: string
110
+ * *italic*: bool, default: false
111
+ * *size*: int
112
+ * *strike_through*: bool, default: false
113
+ * *underline*: :none, :single, :double
114
+ * *alignment*: :none, :subscript, :superscript
115
+
116
+ === Xmlss::Style::Interior
117
+ * *color*: hex string
118
+ * *pattern*: symbol (see code for options), default: :default
119
+ * *pattern_color*: hex string
120
+
121
+ === Xmlss::Style::NumberFormat
122
+ * *format*: :symbol (see code for options)
123
+
124
+ === Xmlss::Style::Protection
125
+ * *protected*: bool, default: false
126
+
127
+
128
+ == For More Info
129
+ * Full XML Spreadsheet spec: http://msdn.microsoft.com/en-us/library/aa140066(office.10).aspx
130
+
131
+ == License
132
+
133
+ Copyright (c) 2011 Kelly D. Redding
134
+
135
+ Permission is hereby granted, free of charge, to any person
136
+ obtaining a copy of this software and associated documentation
137
+ files (the "Software"), to deal in the Software without
138
+ restriction, including without limitation the rights to use,
139
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
140
+ copies of the Software, and to permit persons to whom the
141
+ Software is furnished to do so, subject to the following
142
+ conditions:
143
+
144
+ The above copyright notice and this permission notice shall be
145
+ included in all copies or substantial portions of the Software.
146
+
147
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
148
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
149
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
150
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
151
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
152
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
153
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
154
+ OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'test_belt/rake_tasks'
5
+ TestBelt::RakeTasks.for :test
6
+
7
+ task :default => :build
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'test/env'
3
+
4
+ class ExampleWorkbook < Xmlss::Workbook
5
+ def initialize
6
+ super
7
+ puts "Builing #{self.name}.xml..."
8
+ build
9
+ end
10
+
11
+ def to_file
12
+ # write this workbooks xml data to a file
13
+ File.open("examples/#{self.name}.xml", "w") do |file|
14
+ file.write self.to_xml
15
+ end
16
+ puts "... ready - open in Excel or whatever..."
17
+ end
18
+ end
19
+
@@ -0,0 +1,81 @@
1
+ require 'examples/example_workbook'
2
+
3
+ class Layout < ExampleWorkbook
4
+ def name; "layout"; end
5
+ def build
6
+ wksht = Xmlss::Worksheet.new('first')
7
+ 4.times do
8
+ wksht.table.columns << Xmlss::Column.new
9
+ end
10
+
11
+ 5.times do
12
+ wksht.table.rows << Xmlss::Row.new
13
+ end
14
+
15
+ # | A | B | C | D |
16
+ # 1| x | x | x | x |
17
+ # 2| x | x | x |
18
+ # 3| x | | x |
19
+ # 4| x | x | x |
20
+ # 5| x | | x |
21
+
22
+ # row 1: one cell per column
23
+ 4.times do |i|
24
+ wksht.table.rows[0].cells << Xmlss::Cell.new({
25
+ :index => i+1,
26
+ :data => Xmlss::Data.new("x")
27
+ })
28
+ end
29
+
30
+ # row 2: first cell colspan=2
31
+ wksht.table.rows[1].cells << Xmlss::Cell.new({
32
+ :index => 1,
33
+ :data => Xmlss::Data.new("x"),
34
+ :merge_across => 1
35
+ })
36
+ 2.times do |i|
37
+ wksht.table.rows[1].cells << Xmlss::Cell.new({
38
+ :index => i+3,
39
+ :data => Xmlss::Data.new("x")
40
+ })
41
+ end
42
+
43
+ # row 3,4,5: more complex merging
44
+ # => row 3
45
+ wksht.table.rows[2].cells << Xmlss::Cell.new({
46
+ :data => Xmlss::Data.new("x"),
47
+ :index => 1
48
+ })
49
+ wksht.table.rows[2].cells << Xmlss::Cell.new({
50
+ :data => Xmlss::Data.new("x"),
51
+ :merge_across => 1,
52
+ :merge_down => 2,
53
+ :index => 2
54
+ })
55
+ wksht.table.rows[2].cells << Xmlss::Cell.new({
56
+ :data => Xmlss::Data.new("x"),
57
+ :index => 4
58
+ })
59
+ # => row 4
60
+ wksht.table.rows[3].cells << Xmlss::Cell.new({
61
+ :data => Xmlss::Data.new("x"),
62
+ :index => 1
63
+ })
64
+ wksht.table.rows[3].cells << Xmlss::Cell.new({
65
+ :data => Xmlss::Data.new("x"),
66
+ :index => 4
67
+ })
68
+ # => row 5
69
+ wksht.table.rows[4].cells << Xmlss::Cell.new({
70
+ :data => Xmlss::Data.new("x"),
71
+ :index => 1
72
+ })
73
+ wksht.table.rows[4].cells << Xmlss::Cell.new({
74
+ :data => Xmlss::Data.new("x"),
75
+ :index => 4
76
+ })
77
+
78
+ self.worksheets << wksht
79
+ end
80
+ end
81
+ Layout.new.to_file
@@ -0,0 +1,30 @@
1
+ require 'examples/example_workbook'
2
+
3
+ class Simple < ExampleWorkbook
4
+ def name; "simple"; end
5
+ def build
6
+
7
+ # add 1 row of simple data across 3 columns
8
+ wksht = Xmlss::Worksheet.new('1 row, 3 columns')
9
+
10
+ wksht.table.columns << Xmlss::Column.new
11
+ wksht.table.columns << Xmlss::Column.new
12
+ wksht.table.columns << Xmlss::Column.new
13
+ wksht.table.columns << Xmlss::Column.new
14
+ wksht.table.columns << Xmlss::Column.new
15
+
16
+ row1 = Xmlss::Row.new
17
+
18
+ # put data into the row (infer type)
19
+ [1, "text", 123.45, "0001267", "$45.23"].each do |data|
20
+ row1.cells << Xmlss::Cell.new({
21
+ :data => Xmlss::Data.new(data)
22
+ })
23
+ end
24
+
25
+ wksht.table.rows << row1
26
+ self.worksheets << wksht
27
+
28
+ end
29
+ end
30
+ Simple.new.to_file
@@ -0,0 +1,85 @@
1
+ require 'examples/example_workbook'
2
+
3
+ class Styles < ExampleWorkbook
4
+ def name; "styles"; end
5
+ def build
6
+
7
+ wksht = Xmlss::Worksheet.new('styles')
8
+ wksht.table.columns << Xmlss::Column.new
9
+
10
+ self.styles << Xmlss::Style::Base.new('centered') do
11
+ alignment(
12
+ :horizontal => :center,
13
+ :vertical => :center
14
+ )
15
+ end
16
+ wksht.table.rows << Xmlss::Row.new
17
+ wksht.table.rows[0].cells << Xmlss::Cell.new({
18
+ :style_id => "centered",
19
+ :data => Xmlss::Data.new("x")
20
+ })
21
+
22
+ self.styles << Xmlss::Style::Base.new('bordered') do
23
+ alignment(:wrap_text => true)
24
+ border(
25
+ :position => :top,
26
+ :weight => :hairline,
27
+ :line_style => :continuous
28
+ )
29
+ border(
30
+ :position => :right,
31
+ :weight => :medium,
32
+ :line_style => :continuous
33
+ )
34
+ border(
35
+ :position => :bottom,
36
+ :weight => :thick,
37
+ :line_style => :dash_dot,
38
+ :color => '#00FF00'
39
+ )
40
+ border(
41
+ :position => :left,
42
+ :weight => :thin,
43
+ :line_style => :dot
44
+ )
45
+ end
46
+ wksht.table.rows << Xmlss::Row.new
47
+ wksht.table.rows[1].cells << Xmlss::Cell.new({
48
+ :style_id => "bordered",
49
+ :data => Xmlss::Data.new(%{blah blah blah blah blah\nblah blah blah blah\nblah blah blah blah})
50
+ })
51
+
52
+ self.styles << Xmlss::Style::Base.new('fonted') do
53
+ font(
54
+ :bold => true,
55
+ :color => "#FF0000",
56
+ :italic => true,
57
+ :size => 18,
58
+ :strike_through => true,
59
+ :underline => true
60
+ )
61
+ end
62
+ wksht.table.rows << Xmlss::Row.new
63
+ wksht.table.rows[2].cells << Xmlss::Cell.new({
64
+ :style_id => "fonted",
65
+ :data => Xmlss::Data.new("Cool Font Styles!!")
66
+ })
67
+
68
+ self.styles << Xmlss::Style::Base.new('interior') do
69
+ interior(
70
+ :color => "#FF0000",
71
+ :pattern => :diag_cross,
72
+ :pattern_color => '#00FFFF'
73
+ )
74
+ font(:color => "#FFFFFF")
75
+ end
76
+ wksht.table.rows << Xmlss::Row.new
77
+ wksht.table.rows[3].cells << Xmlss::Cell.new({
78
+ :style_id => "interior",
79
+ :data => Xmlss::Data.new("Weird Styles Man...")
80
+ })
81
+
82
+ self.worksheets << wksht
83
+ end
84
+ end
85
+ Styles.new.to_file
data/examples/text.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'examples/example_workbook'
2
+
3
+ class Text < ExampleWorkbook
4
+ def name; "text"; end
5
+ def build
6
+
7
+ # add in general text style
8
+ self.styles << Xmlss::Style::Base.new('general_text') do
9
+ alignment(
10
+ :horizontal => :left,
11
+ :vertical => :top,
12
+ :wrap_text => true
13
+ )
14
+ number_format(
15
+ :format => "@" # set format to text explicitly
16
+ )
17
+ end
18
+
19
+ # add single cell with text data and specify general text style
20
+ wksht = Xmlss::Worksheet.new('text')
21
+ wksht.table.columns << Xmlss::Column.new
22
+ row1 = Xmlss::Row.new
23
+ row1.cells << Xmlss::Cell.new({
24
+ :style_id => "general_text",
25
+ :data => Xmlss::Data.new(%{
26
+ A blob of text
27
+ with line breaks
28
+ and leading space
29
+ })
30
+ })
31
+ wksht.table.rows << row1
32
+ self.worksheets << wksht
33
+
34
+ end
35
+ end
36
+ Text.new.to_file
data/lib/xmlss/cell.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'xmlss/data'
2
+
3
+ module Xmlss
4
+ class Cell
5
+
6
+ include Xmlss::Xml
7
+ def xml
8
+ { :node => :cell,
9
+ :attributes => [:index, :style_i_d, :formula, :h_ref, :merge_across, :merge_down],
10
+ :children => [:data] }
11
+ end
12
+
13
+ attr_accessor :style_id, :formula, :href, :merge_across, :merge_down
14
+ attr_accessor :index, :data
15
+ alias_method :style_i_d, :style_id
16
+ alias_method :h_ref, :href
17
+
18
+ def initialize(attrs={})
19
+ self.index = attrs[:index]
20
+ self.style_id = attrs[:style_id]
21
+ self.formula = attrs[:formula]
22
+ self.href = attrs[:href]
23
+ self.merge_across = attrs[:merge_across] || 0
24
+ self.merge_down = attrs[:merge_down] || 0
25
+ self.data = attrs[:data]
26
+ end
27
+
28
+ [:index, :merge_across, :merge_down].each do |meth|
29
+ define_method("#{meth}=") do |value|
30
+ if value && !value.kind_of?(::Fixnum)
31
+ raise ArgumentError, "must specify #{meth} as a Fixnum"
32
+ end
33
+ instance_variable_set("@#{meth}", value && value <= 0 ? nil : value)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ module Xmlss
2
+ class Column
3
+
4
+ include Xmlss::Xml
5
+ def xml
6
+ { :node => :column,
7
+ :attributes => [:style_i_d, :width, :auto_fit_width, :hidden] }
8
+ end
9
+
10
+ attr_accessor :style_id, :width, :auto_fit_width, :hidden
11
+ alias_method :style_i_d, :style_id
12
+
13
+ def initialize(attrs={})
14
+ self.style_id = attrs[:style_id]
15
+ self.width = attrs[:width]
16
+ self.auto_fit_width = attrs[:auto_fit_width] || false
17
+ self.hidden = attrs[:hidden] || false
18
+ end
19
+
20
+ def width=(value)
21
+ if value && !value.kind_of?(::Numeric)
22
+ raise ArgumentError, "must specify width as a Numeric"
23
+ end
24
+ @width = value && value < 0 ? nil : value
25
+ end
26
+
27
+ end
28
+ end
data/lib/xmlss/data.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'date'
2
+
3
+ module Xmlss
4
+ class Data
5
+
6
+ LB = "&#13;"
7
+
8
+ include Xmlss::Xml
9
+ def xml
10
+ { :node => :data,
11
+ :attributes => [:type],
12
+ :value => :xml_value }
13
+ end
14
+
15
+ include Xmlss::Enum
16
+ enum :type, {
17
+ :number => "Number",
18
+ :date_time => "DateTime",
19
+ :boolean => "Boolean",
20
+ :string => "String",
21
+ :error => "Error"
22
+ }
23
+
24
+ attr_accessor :value
25
+
26
+ def initialize(value="", attrs={})
27
+ self.value = value
28
+ self.type = attrs[:type] if attrs[:type]
29
+ end
30
+
31
+ def value=(v)
32
+ if self.type.nil?
33
+ self.type = value_type(v)
34
+ end
35
+ @value = v
36
+ end
37
+
38
+ def xml_value
39
+ case value
40
+ when ::Date, ::Time, ::DateTime
41
+ value.strftime("%Y-%m-%dT%H:%M:%S")
42
+ when ::String, ::Symbol
43
+ value.to_s.gsub(/(\r|\n)+/, LB)
44
+ else
45
+ value.to_s
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def value_type(v)
52
+ case v
53
+ when ::Numeric
54
+ :number
55
+ when ::Date, ::Time
56
+ :date_time
57
+ when ::TrueClass, ::FalseClass
58
+ :boolean
59
+ when ::String, ::Symbol
60
+ :string
61
+ else
62
+ :string
63
+ end
64
+ end
65
+
66
+ end
67
+ end
data/lib/xmlss/enum.rb ADDED
@@ -0,0 +1,56 @@
1
+ # common methods used for handling enum data
2
+ module Xmlss
3
+ module Enum
4
+
5
+ module ClassMethods
6
+ def enum(name, map)
7
+ # TODO: validate name
8
+ unless map.kind_of?(::Hash)
9
+ raise ArguementError, "please specify the enum map as a Hash"
10
+ end
11
+
12
+ # define an anonymous Module to extend on
13
+ # defining a class level map reader
14
+ class_methods = Module.new do
15
+ define_method(name) do |key|
16
+ class_variable_get("@@#{name}")[key]
17
+ end
18
+ end
19
+
20
+ # set a class variable to store the enum map (used by above reader)
21
+ # extend the anonymous module to get tne above class
22
+ # level reader for the map
23
+ class_eval do
24
+ class_variable_set("@@#{name}", map)
25
+ extend class_methods
26
+ end
27
+
28
+ # instance writer for the enum value
29
+ define_method("#{name}=") do |value|
30
+ map = self.class.send(:class_variable_get, "@@#{name}")
31
+ instance_variable_set("@#{name}", if value && map.has_key?(value)
32
+ # write by key
33
+ map[value]
34
+ elsif map.has_value?(value)
35
+ # write by value
36
+ value
37
+ else
38
+ nil
39
+ end)
40
+ end
41
+
42
+ # instance reader for the enum value
43
+ define_method(name) do
44
+ instance_variable_get("@#{name}")
45
+ end
46
+ end
47
+ end
48
+
49
+ class << self
50
+ def included(receiver)
51
+ receiver.send :extend, ClassMethods
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ module Xmlss
2
+ class ItemSet < ::Array
3
+ include Xmlss::Xml
4
+ def xml
5
+ { :node => name,
6
+ :children => self }
7
+ end
8
+
9
+ attr_accessor :name
10
+
11
+ def initialize(name=nil, *args)
12
+ self.name = name
13
+ super *args
14
+ end
15
+
16
+ end
17
+ end