ruport 0.4.23 → 0.4.99
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +16 -8
- data/CHANGELOG +30 -1
- data/README +144 -114
- data/Rakefile +12 -4
- data/TODO +4 -7
- data/bin/rope +21 -28
- data/examples/line_graph.rb +36 -0
- data/examples/sample_invoice_report.rb +1 -1
- data/examples/simple_graph.rb +8 -0
- data/lib/SVG/Graph/Bar.rb +137 -0
- data/lib/SVG/Graph/BarBase.rb +140 -0
- data/lib/SVG/Graph/BarHorizontal.rb +136 -0
- data/lib/SVG/Graph/Graph.rb +977 -0
- data/lib/SVG/Graph/Line.rb +444 -0
- data/lib/SVG/Graph/Pie.rb +394 -0
- data/lib/SVG/Graph/Plot.rb +494 -0
- data/lib/SVG/Graph/Schedule.rb +373 -0
- data/lib/SVG/Graph/TimeSeries.rb +241 -0
- data/lib/ruport.rb +2 -2
- data/lib/ruport/config.rb +47 -3
- data/lib/ruport/data/collection.rb +17 -1
- data/lib/ruport/data/record.rb +101 -8
- data/lib/ruport/data/set.rb +81 -2
- data/lib/ruport/data/set.rb.rej +147 -0
- data/lib/ruport/data/set.rb~ +73 -0
- data/lib/ruport/data/table.rb +127 -2
- data/lib/ruport/data/taggable.rb +21 -2
- data/lib/ruport/format.rb +36 -44
- data/lib/ruport/format/engine.rb +21 -1
- data/lib/ruport/format/plugin.rb +64 -1
- data/lib/ruport/mailer.rb +70 -36
- data/lib/ruport/meta_tools.rb +15 -6
- data/lib/ruport/query.rb +1 -1
- data/lib/ruport/rails/reportable.rb +23 -1
- data/lib/ruport/report.rb +11 -11
- data/lib/ruport/report/invoice.rb +16 -0
- data/lib/ruport/system_extensions.rb +3 -55
- data/test/{tc_database.rb → _test_database.rb} +0 -0
- data/test/{tc_config.rb → test_config.rb} +0 -0
- data/test/{tc_format.rb → test_format.rb} +1 -0
- data/test/{tc_format_engine.rb → test_format_engine.rb} +14 -2
- data/test/test_graph.rb +101 -0
- data/test/{tc_invoice.rb → test_invoice.rb} +7 -1
- data/test/test_mailer.rb +108 -0
- data/test/test_meta_tools.rb +14 -0
- data/test/{tc_plugin.rb → test_plugin.rb} +12 -1
- data/test/{tc_query.rb → test_query.rb} +0 -0
- data/test/{tc_record.rb → test_record.rb} +9 -0
- data/test/{tc_report.rb → test_report.rb} +2 -1
- data/test/{tc_ruport.rb → test_ruport.rb} +0 -0
- data/test/test_set.rb +118 -0
- data/test/test_set.rb.rej +16 -0
- data/test/{tc_set.rb → test_set.rb~} +17 -0
- data/test/{tc_sql_split.rb → test_sql_split.rb} +0 -0
- data/test/{tc_table.rb → test_table.rb} +15 -0
- data/test/{tc_taggable.rb → test_taggable.rb} +0 -0
- data/test/unit.log +361 -0
- metadata +52 -30
- data/examples/bar.pdf +0 -193
- data/examples/f.log +0 -5
- data/examples/foo.pdf +0 -193
- data/lib/ruport/format/document.rb +0 -78
- data/lib/ruport/format/open_node.rb +0 -38
- data/test/tc_data_row.rb +0 -132
- data/test/tc_data_set.rb +0 -386
- data/test/tc_document.rb +0 -42
- data/test/tc_element.rb +0 -18
- data/test/tc_page.rb +0 -42
- data/test/tc_section.rb +0 -45
- data/test/ts_all.rb +0 -12
- data/test/ts_format.rb +0 -7
@@ -1,10 +1,26 @@
|
|
1
1
|
module Ruport
|
2
2
|
class Report
|
3
3
|
module Invoice
|
4
|
+
|
5
|
+
# Returns a Format::Engine::Invoice object
|
6
|
+
#
|
7
|
+
# If a block is given, it is possible to customize this object before it
|
8
|
+
# is returned
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# inv = build_invoice do |i|
|
13
|
+
# i.company_info = "Foo Inc.\n42 Front Street\nNew Haven CT"
|
14
|
+
# i.customer_info = "Joe User\njoe@test.com"
|
15
|
+
# i.data = [["Aspirin","$2.00"]].to_table(%w[item cost])
|
16
|
+
# end
|
4
17
|
def build_invoice
|
5
18
|
a = Ruport::Format.invoice_object(:plugin => :pdf)
|
6
19
|
yield(a); return a
|
7
20
|
end
|
21
|
+
|
22
|
+
# Takes a block and calls build_invoice then calls render on the resulting
|
23
|
+
# Format::Engine::Invoice object
|
8
24
|
def render_invoice(&block)
|
9
25
|
build_invoice(&block).render
|
10
26
|
end
|
@@ -9,6 +9,9 @@
|
|
9
9
|
# - Outer Module is changed from HighLine to Ruport
|
10
10
|
# - terminal_width / terminal_height added
|
11
11
|
#
|
12
|
+
# The following modifications have been made by Gregory Brown on 2006.08.13
|
13
|
+
# - removed most methods, preserving only terminal geometry features
|
14
|
+
#
|
12
15
|
# All modifications are under the distributions terms of Ruport.
|
13
16
|
# Copyright 2006, Gregory Brown. All Rights Reserved
|
14
17
|
#
|
@@ -32,18 +35,6 @@ module Ruport
|
|
32
35
|
begin
|
33
36
|
require "Win32API" # See if we're on Windows.
|
34
37
|
|
35
|
-
CHARACTER_MODE = "Win32API" # For Debugging purposes only.
|
36
|
-
|
37
|
-
#
|
38
|
-
# Windows savvy getc().
|
39
|
-
#
|
40
|
-
# *WARNING*: This method ignores <tt>input</tt> and reads one
|
41
|
-
# character from +STDIN+!
|
42
|
-
#
|
43
|
-
def get_character( input = STDIN )
|
44
|
-
Win32API.new("crtdll", "_getch", [ ], "L").Call
|
45
|
-
end
|
46
|
-
|
47
38
|
# A Windows savvy method to fetch the console columns, and rows.
|
48
39
|
def terminal_size
|
49
40
|
m_GetStdHandle = Win32API.new( 'kernel32',
|
@@ -64,49 +55,6 @@ module Ruport
|
|
64
55
|
return right - left + 1, bottom - top + 1
|
65
56
|
end
|
66
57
|
rescue LoadError # If we're not on Windows try...
|
67
|
-
begin
|
68
|
-
require "termios" # Unix, first choice.
|
69
|
-
|
70
|
-
CHARACTER_MODE = "termios" # For Debugging purposes only.
|
71
|
-
|
72
|
-
#
|
73
|
-
# Unix savvy getc(). (First choice.)
|
74
|
-
#
|
75
|
-
# *WARNING*: This method requires the "termios" library!
|
76
|
-
#
|
77
|
-
def get_character( input = STDIN )
|
78
|
-
old_settings = Termios.getattr(input)
|
79
|
-
|
80
|
-
new_settings = old_settings.dup
|
81
|
-
new_settings.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
|
82
|
-
|
83
|
-
begin
|
84
|
-
Termios.setattr(input, Termios::TCSANOW, new_settings)
|
85
|
-
input.getc
|
86
|
-
ensure
|
87
|
-
Termios.setattr(input, Termios::TCSANOW, old_settings)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
rescue LoadError # If our first choice fails, default.
|
91
|
-
CHARACTER_MODE = "stty" # For Debugging purposes only.
|
92
|
-
|
93
|
-
#
|
94
|
-
# Unix savvy getc(). (Second choice.)
|
95
|
-
#
|
96
|
-
# *WARNING*: This method requires the external "stty" program!
|
97
|
-
#
|
98
|
-
def get_character( input = STDIN )
|
99
|
-
state = `stty -g`
|
100
|
-
|
101
|
-
begin
|
102
|
-
system "stty raw -echo cbreak"
|
103
|
-
input.getc
|
104
|
-
ensure
|
105
|
-
system "stty #{state}"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
58
|
# A Unix savvy method to fetch the console columns, and rows.
|
111
59
|
def terminal_size
|
112
60
|
`stty size`.split.map { |x| x.to_i }.reverse
|
File without changes
|
File without changes
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'rubygems' rescue LoadError nil
|
2
1
|
require 'ruport'
|
2
|
+
require 'rubygems' rescue LoadError nil
|
3
3
|
require 'test/unit'
|
4
4
|
|
5
5
|
class MockPlugin < Ruport::Format::Plugin
|
@@ -75,6 +75,15 @@ class TestTabularFormatEngine < Test::Unit::TestCase
|
|
75
75
|
assert_equal "#{@engine.data}", @engine.render
|
76
76
|
end
|
77
77
|
|
78
|
+
# test that attempting to render using an invalid plugin returns an exception
|
79
|
+
# with a useful message
|
80
|
+
def test_render_with_invalid_plugin
|
81
|
+
assert_raises(InvalidPluginError) {
|
82
|
+
Format.table(:plugin => :monkeys,
|
83
|
+
:data => [[1,2,3],[4,5,6],[7,8,9]].to_table(%w[a b c]))
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
78
87
|
def test_simple_interface
|
79
88
|
expected = "#{[[1,2],[3,4]]}"
|
80
89
|
actual = Format.table(:plugin => :mock, :data => [[1,2],[3,4]])
|
@@ -138,7 +147,7 @@ class TestTabularFormatEngine < Test::Unit::TestCase
|
|
138
147
|
assert_equal( [[1,2,3],[nil,2,4],[nil,3,7],
|
139
148
|
[2,1,9],[nil,2,3],[nil,2,9]], @engine.data)
|
140
149
|
|
141
|
-
data = Data::Table.new :column_names => %w[name date service amount]
|
150
|
+
data = Ruport::Data::Table.new :column_names => %w[name date service amount]
|
142
151
|
data << [ "Greg Gibson", "1/1/2000", "Prophy", "100.00" ] <<
|
143
152
|
[ "Greg Gibson", "1/1/2000", "Filling", "100.00" ] <<
|
144
153
|
[ "Greg Gibson", "1/12/2000", "Prophy", "100.00" ] <<
|
@@ -163,6 +172,9 @@ class TestTabularFormatEngine < Test::Unit::TestCase
|
|
163
172
|
end
|
164
173
|
|
165
174
|
class TestDocumentFormatEngine < Test::Unit::TestCase
|
175
|
+
|
176
|
+
include Ruport
|
177
|
+
|
166
178
|
def setup
|
167
179
|
@engine = Format::Engine::Document.dup
|
168
180
|
end
|
data/test/test_graph.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require "ruport"
|
2
|
+
require 'rubygems' rescue LoadError nil
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestGraph < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@data = [[1,2,3,2],[3,4,5,6]].to_table(%w[a b c d])
|
9
|
+
@data_mismatched_headings = [[3,2],[3,4]].to_table(%w[a b c])
|
10
|
+
@data_float = [[1.3,2],[3.28322,4]].to_table(%w[a b])
|
11
|
+
@data_not_numbers = [["d",:sdfs,"not a number","1"],[3,4,5,6]].to_table(%w[a b c d])
|
12
|
+
end
|
13
|
+
|
14
|
+
# basic test to ensure bar charts render
|
15
|
+
def test_bar
|
16
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data
|
17
|
+
graph.options = {:graph_style => :bar}
|
18
|
+
output = graph.render
|
19
|
+
|
20
|
+
assert_not_equal nil, output
|
21
|
+
end
|
22
|
+
|
23
|
+
# basic test to ensure horizontal pie charts render
|
24
|
+
def test_bar_horizontal
|
25
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data
|
26
|
+
graph.options = {:graph_style => :bar_horizontal}
|
27
|
+
output = graph.render
|
28
|
+
|
29
|
+
assert_not_equal nil, output
|
30
|
+
end
|
31
|
+
|
32
|
+
# basic test to ensure line charts render
|
33
|
+
def test_line
|
34
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data
|
35
|
+
graph.options = {:graph_style => :line}
|
36
|
+
output = graph.render
|
37
|
+
|
38
|
+
assert_not_equal nil, output
|
39
|
+
end
|
40
|
+
|
41
|
+
# basic test to ensure pie charts render
|
42
|
+
def test_pie
|
43
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data
|
44
|
+
graph.options = {:graph_style => :pie}
|
45
|
+
output = graph.render
|
46
|
+
|
47
|
+
assert_not_equal nil, output
|
48
|
+
end
|
49
|
+
|
50
|
+
# ensure an exception is raised if the user doesn't name every column
|
51
|
+
def test_mismatched_headings
|
52
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data_mismatched_headings
|
53
|
+
graph.options = {:graph_style => :line}
|
54
|
+
|
55
|
+
assert_raises(ArgumentError) {
|
56
|
+
output = graph.render
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
# test to ensure floats can be graphed
|
61
|
+
def test_floats
|
62
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data_float
|
63
|
+
graph.options = {:graph_style => :line}
|
64
|
+
output = graph.render
|
65
|
+
|
66
|
+
assert_not_equal nil, output
|
67
|
+
end
|
68
|
+
|
69
|
+
# ensure an exception is raised if non numeric data is graphed
|
70
|
+
def test_not_numbers
|
71
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data_not_numbers
|
72
|
+
graph.options = {:graph_style => :line}
|
73
|
+
|
74
|
+
assert_raises(ArgumentError) {
|
75
|
+
output = graph.render
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
# ensure an exception is raised if user tries to render a graph without setting any options
|
80
|
+
def test_no_options
|
81
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data
|
82
|
+
|
83
|
+
assert_raises(RuntimeError) {
|
84
|
+
output = graph.render
|
85
|
+
}
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
# test to make sure user requested options are applied to the resulting graph
|
90
|
+
def test_options_applied_to_rendered_graph
|
91
|
+
graph = Ruport::Format.graph_object :plugin => :svg, :data => @data
|
92
|
+
graph.options = {:graph_style => :line, :graph_title => 'Test', :show_graph_title => true, :no_css => true}
|
93
|
+
output = graph.render
|
94
|
+
|
95
|
+
# ensure the requested graph title is included in the SVG output. If that's there, we can
|
96
|
+
# assume the rest are as well
|
97
|
+
assert_not_equal nil, output[/class='mainTitle'/]
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'ruport'
|
1
2
|
require 'rubygems' rescue LoadError nil
|
2
3
|
require "test/unit"
|
3
4
|
|
@@ -6,8 +7,13 @@ class SampleInvoiceReport < Ruport::Report
|
|
6
7
|
end
|
7
8
|
|
8
9
|
class TestInvoice < Test::Unit::TestCase
|
9
|
-
|
10
|
+
|
10
11
|
def test_basic
|
12
|
+
begin
|
13
|
+
require "pdf/writer"
|
14
|
+
rescue LoadError
|
15
|
+
warn "skipping pdf test"; return
|
16
|
+
end
|
11
17
|
inv = SampleInvoiceReport.build_invoice do |i|
|
12
18
|
i.company_info = "Foo Inc.\n42 Bar Street\nBaz, CT\n"
|
13
19
|
i.customer_info = "Gregory Brown\ngregory.t.brown@gmail.com"
|
data/test/test_mailer.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ruport"
|
3
|
+
begin; require "rubygems"; rescue LoadError; nil end
|
4
|
+
|
5
|
+
class TestMailer < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@default_opts = {
|
9
|
+
:host => "mail.example.com",
|
10
|
+
:address => "sue@example.com",
|
11
|
+
:user => "inky",
|
12
|
+
:password => "chunky"
|
13
|
+
}
|
14
|
+
|
15
|
+
@other_opts = {
|
16
|
+
:host => "moremail.example.com",
|
17
|
+
:address => "clyde@example.com",
|
18
|
+
:user => "blinky",
|
19
|
+
:password => "bacon"
|
20
|
+
}
|
21
|
+
|
22
|
+
Ruport::Config.mailer :default, @default_opts
|
23
|
+
Ruport::Config.mailer :other, @other_opts
|
24
|
+
|
25
|
+
@default_mailer = Ruport::Mailer.new
|
26
|
+
@other_mailer = Ruport::Mailer.new :other
|
27
|
+
end
|
28
|
+
|
29
|
+
def assert_mailer_equal(expected, mailer)
|
30
|
+
assert_equal expected[:host], mailer.instance_variable_get(:@host)
|
31
|
+
assert_equal expected[:address], mailer.instance_variable_get(:@address)
|
32
|
+
assert_equal expected[:user], mailer.instance_variable_get(:@user)
|
33
|
+
assert_equal expected[:password], mailer.instance_variable_get(:@password)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_default_constructor
|
37
|
+
assert_mailer_equal @default_opts, @default_mailer
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_constructor_with_mailer_label
|
41
|
+
assert_mailer_equal @other_opts, @other_mailer
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_select_mailer
|
45
|
+
mailer = Ruport::Mailer.new :default
|
46
|
+
assert_mailer_equal @default_opts, mailer
|
47
|
+
|
48
|
+
mailer.send(:select_mailer, :other)
|
49
|
+
assert_mailer_equal @other_opts, mailer
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_to
|
53
|
+
@default_mailer.instance_eval "@mail.to = ['foo@bar.com']"
|
54
|
+
assert_equal ['foo@bar.com'], @default_mailer.to
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_to_equals
|
58
|
+
@default_mailer.to = ['foo@bar.com']
|
59
|
+
assert_equal ['foo@bar.com'], @default_mailer.to
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_from
|
63
|
+
@default_mailer.instance_eval "@mail.from = ['foo@bar.com']"
|
64
|
+
assert_equal ['foo@bar.com'], @default_mailer.from
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_from_equals
|
68
|
+
@default_mailer.from = ['foo@bar.com']
|
69
|
+
assert_equal ['foo@bar.com'], @default_mailer.from
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_subject
|
73
|
+
@default_mailer.instance_eval "@mail.subject = ['RuportDay!']"
|
74
|
+
assert_equal ['RuportDay!'], @default_mailer.subject
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_subject_equals
|
78
|
+
@default_mailer.subject = ['RuportDay!']
|
79
|
+
assert_equal ['RuportDay!'], @default_mailer.subject
|
80
|
+
end
|
81
|
+
|
82
|
+
# def test_html
|
83
|
+
# @default_mailer.instance_eval "@mail.html = 'RuportDay!'"
|
84
|
+
# assert_equal 'RuportDay!', @default_mailer.html
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# def test_html_equals
|
88
|
+
# @default_mailer.html = 'RuportDay!'
|
89
|
+
# assert_equal 'RuportDay!', @default_mailer.html
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# def test_text
|
93
|
+
# @default_mailer.instance_eval "@mail.text = 'RuportDay!'"
|
94
|
+
# assert_equal 'RuportDay!', @default_mailer.text
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# def test_text_equals
|
98
|
+
# @default_mailer.text = 'RuportDay!'
|
99
|
+
# assert_equal 'RuportDay!', @default_mailer.text
|
100
|
+
# end
|
101
|
+
|
102
|
+
def test_no_default
|
103
|
+
Ruport::Config.mailers[:default] = nil
|
104
|
+
assert_raise(RuntimeError){ Ruport::Mailer.new }
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ruport"
|
3
|
+
|
4
|
+
class A; extend Ruport::MetaTools; end
|
5
|
+
|
6
|
+
class TestMetaTools < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_action
|
9
|
+
assert_nothing_raised { A.action(:foo) { |x| x + 1 } }
|
10
|
+
assert_equal 4, A.foo(3)
|
11
|
+
assert_raise(ActionAlreadyDefinedError) { A.action(:foo) { } }
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "test/unit"
|
2
2
|
require "ruport"
|
3
|
-
|
3
|
+
require "rubygems" rescue LoadError nil
|
4
4
|
|
5
5
|
include Ruport
|
6
6
|
|
@@ -49,6 +49,11 @@ end
|
|
49
49
|
class PDFPluginTest < Test::Unit::TestCase
|
50
50
|
|
51
51
|
def test_ensure_fails_on_array
|
52
|
+
begin
|
53
|
+
require "pdf/writer"
|
54
|
+
rescue LoadError
|
55
|
+
warn "skipping pdf test"; return
|
56
|
+
end
|
52
57
|
a = Format.table_object :plugin => :pdf, :data => [[1,2],[3,4]]
|
53
58
|
assert_raise(RuntimeError) { a.render }
|
54
59
|
|
@@ -61,6 +66,12 @@ class PDFPluginTest < Test::Unit::TestCase
|
|
61
66
|
end
|
62
67
|
|
63
68
|
def test_hooks
|
69
|
+
begin
|
70
|
+
require "pdf/writer"
|
71
|
+
rescue LoadError
|
72
|
+
warn "skipping pdf test"; return
|
73
|
+
end
|
74
|
+
a = Format.table_object :plugin => :pdf, :data => [[1,2],[3,4]]
|
64
75
|
a = Format.table_object :plugin => :pdf,
|
65
76
|
:data => [[1,2],[3,4]].to_table(:column_names => %w[a b])
|
66
77
|
y = 0
|
File without changes
|
@@ -135,6 +135,15 @@ class RecordTest < Test::Unit::TestCase
|
|
135
135
|
@record.reorder! 3,1,2
|
136
136
|
assert_equal [3,4,2], @record.data
|
137
137
|
assert_equal %w[c d b], @record.attributes
|
138
|
+
|
139
|
+
r.reorder! %w[a b c]
|
140
|
+
assert_equal [1,2,3], r.data
|
141
|
+
assert_equal %w[a b c], r.attributes
|
142
|
+
|
143
|
+
assert_raise(ArgumentError) { r.reorder "foo" }
|
144
|
+
assert_raise(ArgumentError) { r.reorder 0,5 }
|
145
|
+
assert_nothing_raised { r.reorder 0 }
|
146
|
+
assert_nothing_raised { r.reorder "a","b" }
|
138
147
|
end
|
139
148
|
|
140
149
|
def test_dup
|