text2path 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +14 -0
  4. data/README.md +40 -0
  5. data/lib/ext/savage/LICENSE +20 -0
  6. data/lib/ext/savage/README.rdoc +108 -0
  7. data/lib/ext/savage/Rakefile +39 -0
  8. data/lib/ext/savage/VERSION +1 -0
  9. data/lib/ext/savage/lib/savage/direction.rb +42 -0
  10. data/lib/ext/savage/lib/savage/direction_proxy.rb +19 -0
  11. data/lib/ext/savage/lib/savage/directions/arc_to.rb +29 -0
  12. data/lib/ext/savage/lib/savage/directions/close_path.rb +18 -0
  13. data/lib/ext/savage/lib/savage/directions/coordinate_target.rb +17 -0
  14. data/lib/ext/savage/lib/savage/directions/cubic_curve_to.rb +40 -0
  15. data/lib/ext/savage/lib/savage/directions/horizontal_to.rb +19 -0
  16. data/lib/ext/savage/lib/savage/directions/line_to.rb +15 -0
  17. data/lib/ext/savage/lib/savage/directions/move_to.rb +15 -0
  18. data/lib/ext/savage/lib/savage/directions/point_target.rb +17 -0
  19. data/lib/ext/savage/lib/savage/directions/quadratic_curve_to.rb +44 -0
  20. data/lib/ext/savage/lib/savage/directions/vertical_to.rb +19 -0
  21. data/lib/ext/savage/lib/savage/parser.rb +108 -0
  22. data/lib/ext/savage/lib/savage/path.rb +50 -0
  23. data/lib/ext/savage/lib/savage/sub_path.rb +54 -0
  24. data/lib/ext/savage/lib/savage/transformable.rb +48 -0
  25. data/lib/ext/savage/lib/savage/utils.rb +7 -0
  26. data/lib/ext/savage/lib/savage.rb +3 -0
  27. data/lib/ext/savage/savage.gemspec +80 -0
  28. data/lib/ext/savage/spec/savage/directions/arc_to_spec.rb +97 -0
  29. data/lib/ext/savage/spec/savage/directions/close_path_spec.rb +30 -0
  30. data/lib/ext/savage/spec/savage/directions/cubic_curve_to_spec.rb +146 -0
  31. data/lib/ext/savage/spec/savage/directions/horizontal_to_spec.rb +10 -0
  32. data/lib/ext/savage/spec/savage/directions/line_to_spec.rb +10 -0
  33. data/lib/ext/savage/spec/savage/directions/move_to_spec.rb +10 -0
  34. data/lib/ext/savage/spec/savage/directions/point_spec.rb +12 -0
  35. data/lib/ext/savage/spec/savage/directions/quadratic_curve_spec.rb +123 -0
  36. data/lib/ext/savage/spec/savage/directions/vertical_to_spec.rb +10 -0
  37. data/lib/ext/savage/spec/savage/parser_spec.rb +250 -0
  38. data/lib/ext/savage/spec/savage/path_spec.rb +105 -0
  39. data/lib/ext/savage/spec/savage/sub_path_spec.rb +195 -0
  40. data/lib/ext/savage/spec/savage/transformable_spec.rb +62 -0
  41. data/lib/ext/savage/spec/savage_spec.rb +5 -0
  42. data/lib/ext/savage/spec/shared/command.rb +13 -0
  43. data/lib/ext/savage/spec/shared/coordinate_target.rb +36 -0
  44. data/lib/ext/savage/spec/shared/direction.rb +29 -0
  45. data/lib/ext/savage/spec/shared/point_target.rb +45 -0
  46. data/lib/ext/savage/spec/spec_helper.rb +36 -0
  47. data/lib/text2path/converter.rb +65 -0
  48. data/lib/text2path/glyph.rb +13 -0
  49. data/lib/text2path/svg_font.rb +92 -0
  50. data/lib/text2path/svg_path.rb +38 -0
  51. data/lib/text2path/version.rb +3 -0
  52. data/lib/text2path.rb +10 -0
  53. data/libpeerconnection.log +0 -0
  54. data/out.svg +1 -0
  55. data/test.rb +6 -0
  56. metadata +127 -0
@@ -0,0 +1,123 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ include Savage::Directions
4
+
5
+ describe QuadraticCurveTo do
6
+ def dir_class; QuadraticCurveTo; end
7
+ def create_relative; QuadraticCurveTo.new(100,200,300,400,false); end
8
+ def command_code; 'q'; end
9
+
10
+ before :each do
11
+ @dir = dir_class.new(100,200,300,400)
12
+ end
13
+
14
+ include Command
15
+ it_behaves_like 'Direction'
16
+
17
+ it 'should have a target' do
18
+ @dir.respond_to?(:target).should == true
19
+ @dir.target.class.should == Point
20
+ end
21
+ it 'should have a control point' do
22
+ @dir.respond_to?(:control).should == true
23
+ @dir.control.class.should == Point
24
+ end
25
+ it 'should have an accessible target x, based on the constructor argument' do
26
+ @dir.target.x.should == 300
27
+ end
28
+ it 'should have an accessible target y, based on the constructor argument' do
29
+ @dir.target.y.should == 400
30
+ end
31
+ context 'when in verbose format' do
32
+ it 'should be constructed with at least target x and y and control x and y parameters' do
33
+ lambda { dir_class.new }.should raise_error
34
+ lambda { dir_class.new 45 }.should raise_error
35
+ lambda { dir_class.new 45, 50, 60 }.should raise_error
36
+ lambda { dir_class.new 45, 50, 60, 70 }.should_not raise_error
37
+ lambda { dir_class.new 45, 50, 60, 70, true }.should_not raise_error
38
+ end
39
+ it 'should be relative if constructed with a false fifth parameter' do
40
+ direction = dir_class.new 45, 50, 60, 70, false
41
+ direction.absolute?.should == false
42
+ end
43
+ it 'should be absolute if constructed with a true fifth parameter' do
44
+ direction = dir_class.new 45, 50, 60, 70, true
45
+ direction.absolute?.should == true
46
+ end
47
+ it 'should be absolute if constructed with only four parameters' do
48
+ direction = dir_class.new 45, 50, 60, 70
49
+ direction.absolute?.should == true
50
+ end
51
+ it 'should have an accessible first control x, based on the constructor argument' do
52
+ @dir.control.x.should == 100
53
+ end
54
+ it 'should have an accessible first control y, based on the constructor argument' do
55
+ @dir.control.y.should == 200
56
+ end
57
+ describe '#to_command' do
58
+ it 'should start with a lower-case q when not absolute' do
59
+ extract_command(QuadraticCurveTo.new(100,200,300,400,false).to_command).should == 'q'
60
+ end
61
+ it 'should start with a capital Q when absolute' do
62
+ extract_command(@dir.to_command).should == 'Q'
63
+ end
64
+ it 'should have exactly 4 numerical parameters' do
65
+ extract_coordinates(@dir.to_command).length.should == 4
66
+ end
67
+ it 'should show the provided control X value as the first parameter' do
68
+ extract_coordinates(@dir.to_command)[0].should == 100
69
+ end
70
+ it 'should show the provided control Y value as the second parameter' do
71
+ extract_coordinates(@dir.to_command)[1].should == 200
72
+ end
73
+ it 'should show the provided target X value as the third parameter' do
74
+ extract_coordinates(@dir.to_command)[2].should == 300
75
+ end
76
+ it 'should show the provided target Y value as the fourth parameter' do
77
+ extract_coordinates(@dir.to_command)[3].should == 400
78
+ end
79
+ end
80
+ end
81
+ context 'when in shorthand format' do
82
+ before :each do
83
+ @dir = QuadraticCurveTo.new(100,200)
84
+ end
85
+ it 'should be constructed with at least target x and y parameters' do
86
+ lambda { dir_class.new }.should raise_error
87
+ lambda { dir_class.new 45 }.should raise_error
88
+ lambda { dir_class.new 45, 50 }.should_not raise_error
89
+ end
90
+ it 'should be relative if constructed with a false third parameter' do
91
+ direction = dir_class.new 45, 50, false
92
+ direction.absolute?.should == false
93
+ end
94
+ it 'should be absolute if constructed with a true third parameter' do
95
+ direction = dir_class.new 45, 50, true
96
+ direction.absolute?.should == true
97
+ end
98
+ it 'should be absolute if constructed with only two parameters' do
99
+ direction = dir_class.new 45, 50
100
+ direction.absolute?.should == true
101
+ end
102
+ it 'should have an nil control, based on the constructor argument' do
103
+ @dir.control.should == nil
104
+ end
105
+ describe '#to_command' do
106
+ it 'should start with a lower-case t when not absolute' do
107
+ extract_command(QuadraticCurveTo.new(100,200,false).to_command).should == 't'
108
+ end
109
+ it 'should start with a capital T when absolute' do
110
+ extract_command(@dir.to_command).should == 'T'
111
+ end
112
+ it 'should have exactly 2 numerical parameters' do
113
+ extract_coordinates(@dir.to_command).length.should == 2
114
+ end
115
+ it 'should show the provided target X value as the first parameter' do
116
+ extract_coordinates(@dir.to_command)[0].should == 100
117
+ end
118
+ it 'should show the provided target Y value as the second parameter' do
119
+ extract_coordinates(@dir.to_command)[1].should == 200
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ include Savage::Directions
4
+
5
+ describe VerticalTo do
6
+ def dir_class; VerticalTo; end
7
+ def create_relative; VerticalTo.new(100,false); end
8
+ def command_code; 'v'; end
9
+ it_behaves_like 'CoordinateTarget'
10
+ end
@@ -0,0 +1,250 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Savage
4
+
5
+ describe Parser do
6
+ it 'should have a parse method' do
7
+ Parser.respond_to?(:parse).should == true
8
+ end
9
+ describe '.parse' do
10
+ it 'should accept a single string as argument' do
11
+ lambda { Parser.parse }.should raise_error
12
+ lambda { Parser.parse("M100 200") }.should_not raise_error
13
+ lambda { Parser.parse(2) }.should raise_error
14
+ end
15
+
16
+ it 'should return a path object with one subpath containing one move_to when the string is only a move_to command' do
17
+ path = Parser.parse("M100 200")
18
+ path.class.should == Path
19
+ path.subpaths.length.should == 1
20
+ path.subpaths.last.directions.length.should == 1
21
+ path.subpaths.last.directions.last.class.should == Directions::MoveTo
22
+ end
23
+
24
+ it 'should return a path object with one subpath containing an absolute move_to even when the string starts with a relative move_to command' do
25
+ path = Parser.parse("m100 200")
26
+ path.class.should == Path
27
+ path.subpaths.length.should == 1
28
+ path.subpaths.last.directions.length.should == 1
29
+ path.subpaths.last.directions.last.class.should == Directions::MoveTo
30
+ path.subpaths.last.directions.last.should be_absolute
31
+ end
32
+
33
+ it 'should handle comma separated coordinates' do
34
+ path = Parser.parse("M100,200")
35
+ path.class.should == Path
36
+ path.subpaths.length.should == 1
37
+ path.subpaths.last.directions.length.should == 1
38
+ path.subpaths.last.directions.last.class.should == Directions::MoveTo
39
+ end
40
+
41
+ it 'should return a path object with one subpath containing a move_to and a line_to when the string is a move_to command followed by a line_to command' do
42
+ path = Parser.parse("M100 200l-342.65 21")
43
+ path.class.should == Path
44
+ path.subpaths.length.should == 1
45
+ path.subpaths.last.directions.length.should == 2
46
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
47
+ path.subpaths.last.directions[1].should_not be_absolute
48
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
49
+ end
50
+
51
+ it 'should return a path object with one subpath containing a move_to and a horizontal_to when the string is a move_to command followed by a horizontal_to command' do
52
+ path = Parser.parse("M100 200H-342.65")
53
+ path.class.should == Path
54
+ path.subpaths.length.should == 1
55
+ path.subpaths.last.directions.length.should == 2
56
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
57
+ path.subpaths.last.directions[1].class.should == Directions::HorizontalTo
58
+ end
59
+
60
+ it 'should return a path object with one subpath containing a move_to and a vertical_to when the string is a move_to command followed by a vertical_to command' do
61
+ path = Parser.parse("M100 200V-342.65")
62
+ path.class.should == Path
63
+ path.subpaths.length.should == 1
64
+ path.subpaths.last.directions.length.should == 2
65
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
66
+ path.subpaths.last.directions[1].class.should == Directions::VerticalTo
67
+ end
68
+
69
+ it 'should return a path object with one subpath containing a move_to and a full cubic_curve_to when the string is a move_to command followed by a full cubic_curve_to command' do
70
+ path = Parser.parse("M100 200C-342.65-32 1.233-34 255 12")
71
+ path.class.should == Path
72
+ path.subpaths.length.should == 1
73
+ path.subpaths.last.directions.length.should == 2
74
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
75
+ path.subpaths.last.directions[1].class.should == Directions::CubicCurveTo
76
+ path.subpaths.last.directions[1].command_code.should == 'C'
77
+ end
78
+
79
+ it 'should return a path object with one subpath containing a move_to and a short cubic_curve_to when the string is a move_to command followed by a short cubic_curve_to command' do
80
+ path = Parser.parse("M100 200S1.233-34 255 12")
81
+ path.class.should == Path
82
+ path.subpaths.length.should == 1
83
+ path.subpaths.last.directions.length.should == 2
84
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
85
+ path.subpaths.last.directions[1].class.should == Directions::CubicCurveTo
86
+ path.subpaths.last.directions[1].command_code.should == 'S'
87
+ end
88
+
89
+ it 'should return a path object with one subpath containing a move_to and a full quadratic_curve_to when the string is a move_to command followed by a full quadratic_curve_to command' do
90
+ path = Parser.parse("M100 200Q1.233-34 255 12")
91
+ path.class.should == Path
92
+ path.subpaths.length.should == 1
93
+ path.subpaths.last.directions.length.should == 2
94
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
95
+ path.subpaths.last.directions[1].class.should == Directions::QuadraticCurveTo
96
+ path.subpaths.last.directions[1].command_code.should == 'Q'
97
+ end
98
+
99
+ it 'should return a path object with one subpath containing a move_to and a short quadratic_curve_to when the string is a move_to command followed by a short quadratic_curve_to command' do
100
+ path = Parser.parse("M100 200T255 12")
101
+ path.class.should == Path
102
+ path.subpaths.length.should == 1
103
+ path.subpaths.last.directions.length.should == 2
104
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
105
+ path.subpaths.last.directions[1].class.should == Directions::QuadraticCurveTo
106
+ path.subpaths.last.directions[1].command_code.should == 'T'
107
+ end
108
+ it 'should return a path object with one subpath containing a move_to and an arc_to when the string is a move_to command followed by an arc_to command' do
109
+ path = Parser.parse("M100 200A255 12-123 1 0 23-93.4")
110
+ path.class.should == Path
111
+ path.subpaths.length.should == 1
112
+ path.subpaths.last.directions.length.should == 2
113
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
114
+ path.subpaths.last.directions[1].class.should == Directions::ArcTo
115
+ path.subpaths.last.directions[1].command_code.should == 'A'
116
+ end
117
+
118
+ it 'should return a path object with one subpath containing a move_to, a line_to, and a close_path command when the string is a move_to command followed by a line_to followed by a close_path command' do
119
+ path = Parser.parse("M100 200l-342.65 21Z")
120
+ path.class.should == Path
121
+ path.subpaths.length.should == 1
122
+ path.subpaths.last.directions.length.should == 3
123
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
124
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
125
+ path.subpaths.last.directions[2].class.should == Directions::ClosePath
126
+ path.subpaths.last.closed?.should == true
127
+ end
128
+
129
+ it 'should return a path object with one subpath containing two line_to directions when the string is a line_to command followed by implicit coordinates' do
130
+ path = Parser.parse("L100 200 300 400")
131
+ path.class.should == Path
132
+ path.subpaths.length.should == 1
133
+ path.subpaths.last.directions.length.should == 2
134
+ path.subpaths.last.directions[0].class.should == Directions::LineTo
135
+ path.subpaths.last.directions[0].target.x.should == 100
136
+ path.subpaths.last.directions[0].target.y.should == 200
137
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
138
+ path.subpaths.last.directions[1].target.x.should == 300
139
+ path.subpaths.last.directions[1].target.y.should == 400
140
+ end
141
+
142
+ it 'should return a path object with one subpath containing two line_to directions when the string is a line_to command followed by implicit coordinates' do
143
+ path = Parser.parse("L100 200 300 400")
144
+ path.class.should == Path
145
+ path.subpaths.length.should == 1
146
+ path.subpaths.last.directions.length.should == 2
147
+ path.subpaths.last.directions[0].class.should == Directions::LineTo
148
+ path.subpaths.last.directions[0].target.x.should == 100
149
+ path.subpaths.last.directions[0].target.y.should == 200
150
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
151
+ path.subpaths.last.directions[1].target.x.should == 300
152
+ path.subpaths.last.directions[1].target.y.should == 400
153
+ end
154
+
155
+ it 'should return a path object with one subpath containing a move_to and a line_to direction when the string is a move_to command followed by implicit coordinates' do
156
+ path = Parser.parse("M100 200 300 400")
157
+ path.class.should == Path
158
+ path.subpaths.length.should == 1
159
+ path.subpaths.last.directions.length.should == 2
160
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
161
+ path.subpaths.last.directions[0].target.x.should == 100
162
+ path.subpaths.last.directions[0].target.y.should == 200
163
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
164
+ path.subpaths.last.directions[1].target.x.should == 300
165
+ path.subpaths.last.directions[1].target.y.should == 400
166
+ end
167
+
168
+ it 'should return a path object with one subpath containing an absolute move_to and two absolute line_to directions when the string is an absolute move_to command followed by more than one set of implicit coordinates' do
169
+ path = Parser.parse("M100 200 300 400 500 600 ")
170
+ path.class.should == Path
171
+ path.subpaths.length.should == 1
172
+ path.subpaths.last.directions.length.should == 3
173
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
174
+ path.subpaths.last.directions[0].should be_absolute
175
+ path.subpaths.last.directions[0].target.x.should == 100
176
+ path.subpaths.last.directions[0].target.y.should == 200
177
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
178
+ path.subpaths.last.directions[1].should be_absolute
179
+ path.subpaths.last.directions[1].target.x.should == 300
180
+ path.subpaths.last.directions[1].target.y.should == 400
181
+ path.subpaths.last.directions[2].class.should == Directions::LineTo
182
+ path.subpaths.last.directions[2].should be_absolute
183
+ path.subpaths.last.directions[2].target.x.should == 500
184
+ path.subpaths.last.directions[2].target.y.should == 600
185
+ end
186
+
187
+ it 'should return a path object with one subpath containing an absolute move_to and two relative line_to directions when the string is a relative move_to command followed by more than one set of implicit coordinates' do
188
+ path = Parser.parse("m100 200 300 400 500 600 ")
189
+ path.class.should == Path
190
+ path.subpaths.length.should == 1
191
+ path.subpaths.last.directions.length.should == 3
192
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
193
+ path.subpaths.last.directions[0].should be_absolute
194
+ path.subpaths.last.directions[0].target.x.should == 100
195
+ path.subpaths.last.directions[0].target.y.should == 200
196
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
197
+ path.subpaths.last.directions[1].should_not be_absolute
198
+ path.subpaths.last.directions[1].target.x.should == 300
199
+ path.subpaths.last.directions[1].target.y.should == 400
200
+ path.subpaths.last.directions[2].class.should == Directions::LineTo
201
+ path.subpaths.last.directions[2].should_not be_absolute
202
+ path.subpaths.last.directions[2].target.x.should == 500
203
+ path.subpaths.last.directions[2].target.y.should == 600
204
+ end
205
+
206
+ it 'should return a path object with two subpaths containing one line_to directions each when the string is two move_to commands each followed by a line_to command' do
207
+ path = Parser.parse("M100 200 332 -12.3m594 230-423 11.1")
208
+ path.class.should == Path
209
+ path.subpaths.length.should == 2
210
+ path.subpaths[0].directions.length.should == 2
211
+ path.subpaths[0].directions[0].class.should == Directions::MoveTo
212
+ path.subpaths[0].directions[0].should be_absolute
213
+ path.subpaths[0].directions[0].target.x.should == 100
214
+ path.subpaths[0].directions[0].target.y.should == 200
215
+ path.subpaths[0].directions[1].class.should == Directions::LineTo
216
+ path.subpaths[0].directions[1].should be_absolute
217
+ path.subpaths[0].directions[1].target.x.should == 332
218
+ path.subpaths[0].directions[1].target.y.should == -12.3
219
+ path.subpaths[1].directions[0].class.should == Directions::MoveTo
220
+ path.subpaths[1].directions[0].should_not be_absolute
221
+ path.subpaths[1].directions[0].target.x.should == 594
222
+ path.subpaths[1].directions[0].target.y.should == 230
223
+ path.subpaths[1].directions[1].class.should == Directions::LineTo
224
+ path.subpaths[1].directions[1].should_not be_absolute
225
+ path.subpaths[1].directions[1].target.x.should == -423
226
+ path.subpaths[1].directions[1].target.y.should == 11.1
227
+ end
228
+
229
+ it 'should generate the same string given to it (assuming float values are used), if not changed in the interim' do
230
+ path_string = "M100 200A255 12-123 1 0 23-93.4L100 200 300 400Q1.233-34 255 12T255 12H-342.65Z"
231
+ path = Parser.parse(path_string)
232
+ path.to_command.should == path_string
233
+ end
234
+
235
+ it "should be able to parse complex paths" do
236
+ path = Parser.parse("M74.89,146.249c042,0.552,0.376,0.685,0.744,0.293m50.543-9.1323c15.445-16.43,32.782-32.859,49.793-49.289 c-6.298,001-12.595,001-18.893,0c-10.813,10.37-21.759,20.737-32.275,31.107C74.249,134.323,74.424,140.285,74.89,146.249z")
237
+ path.class.should == Path
238
+ path.subpaths.length.should == 2
239
+ path.subpaths[0].directions.length.should == 2
240
+ path.subpaths[1].directions.length.should == 6
241
+ end
242
+
243
+ it "should support scientific notation in paths (eg. 2e-5)" do
244
+ # this is a 100x100 square
245
+ path = Parser.parse "M 0,0 L 1e2,0 100,1000e-1 L 0,10e+1"
246
+ points = path.directions.map{|d| [d.target.x, d.target.y] }
247
+ points.should == [[0, 0], [100, 0], [100, 100], [0, 100]]
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,105 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Savage
4
+
5
+ describe Path do
6
+ it 'should accept no parameters in a constructor for a new, empty path' do
7
+ lambda{ Path.new }.should_not raise_error
8
+ end
9
+ it 'should be able to be constructed with a starting point (absolute move to)' do
10
+ path = Path.new(100,200)
11
+ path.subpaths.length.should == 1
12
+ path.subpaths.last.directions.length.should == 1
13
+ path.subpaths.last.directions.last.class.should == Directions::MoveTo
14
+ end
15
+ it 'should be able to build itself in a block' do
16
+ path = Path.new(100,200) do |p|
17
+ p.line_to 300, 400
18
+ p.cubic_curve_to 500,600,700,800,900,1000
19
+ p.arc_to 100,200,123,1,1,300,400
20
+ end
21
+ path.subpaths.last.directions[0].class.should == Directions::MoveTo
22
+ path.subpaths.last.directions[1].class.should == Directions::LineTo
23
+ path.subpaths.last.directions[2].class.should == Directions::CubicCurveTo
24
+ path.subpaths.last.directions[3].class.should == Directions::ArcTo
25
+
26
+ path2 = Path.new do |p|
27
+ p.line_to 300, 400
28
+ p.cubic_curve_to 500,600,700,800,900,1000
29
+ p.arc_to 100,200,123,1,1,300,400
30
+ end
31
+ path2.subpaths.last.directions[0].class.should == Directions::LineTo
32
+ path2.subpaths.last.directions[1].class.should == Directions::CubicCurveTo
33
+ path2.subpaths.last.directions[2].class.should == Directions::ArcTo
34
+ end
35
+ it 'should have a directions list' do
36
+ Path.new.respond_to?(:directions).should == true
37
+ end
38
+ it 'should have a move_to method' do
39
+ Path.new.respond_to?(:move_to).should == true
40
+ end
41
+ it 'should have a line_to method' do
42
+ Path.new.respond_to?(:line_to).should == true
43
+ end
44
+ it 'should have a horizontal_to method' do
45
+ Path.new.respond_to?(:horizontal_to).should == true
46
+ end
47
+ it 'should have a vertical_to method' do
48
+ Path.new.respond_to?(:vertical_to).should == true
49
+ end
50
+ it 'should have a quadratic_curve_to method' do
51
+ Path.new.respond_to?(:quadratic_curve_to).should == true
52
+ end
53
+ it 'should have a cubic_curve_to method' do
54
+ Path.new.respond_to?(:cubic_curve_to).should == true
55
+ end
56
+ it 'should have a arc_to method' do
57
+ Path.new.respond_to?(:arc_to).should == true
58
+ end
59
+ it 'should have a close_path method' do
60
+ Path.new.respond_to?(:close_path).should == true
61
+ end
62
+ it 'should have a closed? method' do
63
+ Path.new.respond_to?(:closed?).should == true
64
+ end
65
+ it 'should have subpaths' do
66
+ Path.new.respond_to?(:subpaths).should == true
67
+ end
68
+ it 'should have a to_command method' do
69
+ Path.new.respond_to?(:to_command).should == true
70
+ end
71
+ describe '#move_to' do
72
+ it 'should create a new subpath with that movement therein if there is already a populated subpath' do
73
+ path = Path.new(200,300) do |p|
74
+ p.line_to(123,456)
75
+ p.close_path
76
+ end
77
+ path.move_to(200,300)
78
+ path.subpaths.length.should == 2
79
+ path.subpaths.last.directions.length.should == 1
80
+ path.subpaths.last.directions.last.class.should == Directions::MoveTo
81
+ end
82
+ it 'should create append the movement if the last subpath is empty a populated subpath' do
83
+ path = Path.new
84
+ path.move_to(200,300)
85
+ path.subpaths.length.should == 1
86
+ path.subpaths.last.directions.length.should == 1
87
+ path.subpaths.last.directions.last.class.should == Directions::MoveTo
88
+ end
89
+ end
90
+ describe '#to_command' do
91
+ it 'should concatenate all its subpaths command strings' do
92
+ path = Path.new(100,200) do |p|
93
+ p.line_to 300, 400
94
+ p.cubic_curve_to 500,600,700,800,900,1000
95
+ p.arc_to 100,200,123,1,1,300,400
96
+ p.close_path
97
+ p.move_to 499, 232
98
+ p.line_to 2433.4, -231
99
+ p.line_to -233, 122
100
+ end
101
+ concatenated = path.subpaths.collect { |subpath| subpath.to_command }.join
102
+ path.to_command.should == concatenated
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,195 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Savage
4
+
5
+ describe SubPath do
6
+ it 'should have a directions list' do
7
+ SubPath.new.respond_to?(:directions).should == true
8
+ end
9
+ it 'should have a move_to method' do
10
+ SubPath.new.respond_to?(:move_to).should == true
11
+ end
12
+ it 'should have a line_to method' do
13
+ SubPath.new.respond_to?(:line_to).should == true
14
+ end
15
+ it 'should have a horizontal_to method' do
16
+ SubPath.new.respond_to?(:horizontal_to).should == true
17
+ end
18
+ it 'should have a vertical_to method' do
19
+ SubPath.new.respond_to?(:vertical_to).should == true
20
+ end
21
+ it 'should have a quadratic_curve_to method' do
22
+ SubPath.new.respond_to?(:quadratic_curve_to).should == true
23
+ end
24
+ it 'should have a cubic_curve_to method' do
25
+ SubPath.new.respond_to?(:cubic_curve_to).should == true
26
+ end
27
+ it 'should have a arc_to method' do
28
+ SubPath.new.respond_to?(:arc_to).should == true
29
+ end
30
+ it 'should have a close_path method' do
31
+ SubPath.new.respond_to?(:close_path).should == true
32
+ end
33
+ it 'should have a closed? method' do
34
+ SubPath.new.respond_to?(:closed?).should == true
35
+ end
36
+ it 'should have a to_command method' do
37
+ SubPath.new.respond_to?(:to_command).should == true
38
+ end
39
+ it 'should be able to be constructed empty' do
40
+ lambda { SubPath.new }.should_not raise_error
41
+ end
42
+ it 'should be able to be constructed with a starting point (absolute move to)' do
43
+ path = SubPath.new(100,200)
44
+ path.directions.length.should == 1
45
+ path.directions.last.class.should == Directions::MoveTo
46
+ end
47
+ it 'should be able to build itself in a block' do
48
+ path = SubPath.new(100,200) do |p|
49
+ p.line_to 300, 400
50
+ p.cubic_curve_to 500,600,700,800,900,1000
51
+ p.arc_to 100,200,123,1,1,300,400
52
+ end
53
+ path.directions[0].class.should == Directions::MoveTo
54
+ path.directions[1].class.should == Directions::LineTo
55
+ path.directions[2].class.should == Directions::CubicCurveTo
56
+ path.directions[3].class.should == Directions::ArcTo
57
+
58
+ path2 = SubPath.new do |p|
59
+ p.line_to 300, 400
60
+ p.cubic_curve_to 500,600,700,800,900,1000
61
+ p.arc_to 100,200,123,1,1,300,400
62
+ end
63
+ path2.directions[0].class.should == Directions::LineTo
64
+ path2.directions[1].class.should == Directions::CubicCurveTo
65
+ path2.directions[2].class.should == Directions::ArcTo
66
+ end
67
+ describe '#quadratic_curve_to' do
68
+ it 'should raise an error if in short format and the previous command is of any type by QuadraticCurveTo' do
69
+ path = SubPath.new
70
+ lambda { path.quadratic_curve_to 500, 600 }.should raise_error
71
+ path = SubPath.new
72
+ path.move_to 233, 123
73
+ lambda { path.quadratic_curve_to 500, 600 }.should raise_error
74
+ path = SubPath.new
75
+ path.line_to 443, 265
76
+ lambda { path.quadratic_curve_to 500, 600 }.should raise_error
77
+ path = SubPath.new
78
+ path.cubic_curve_to 100,200,300,400,500,600
79
+ lambda { path.quadratic_curve_to 500, 600 }.should raise_error
80
+ end
81
+ it 'should not raise an error if in short format and the previous command is of type QuadraticCurveTo' do
82
+ path = SubPath.new
83
+ path.quadratic_curve_to 100,200,300,400
84
+ lambda { path.quadratic_curve_to 500, 600 }.should_not raise_error
85
+ end
86
+ end
87
+ describe '#cubic_curve_to' do
88
+ it 'should raise an error if in short format and the previous command is of any type by CubicCurveTo' do
89
+ path = SubPath.new
90
+ lambda { path.cubic_curve_to 500, 600, 700, 800 }.should raise_error
91
+ path = SubPath.new
92
+ path.move_to 233, 123
93
+ lambda { path.cubic_curve_to 500, 600, 700, 800 }.should raise_error
94
+ path = SubPath.new
95
+ path.line_to 443, 265
96
+ lambda { path.cubic_curve_to 500, 600, 700, 800 }.should raise_error
97
+ path = SubPath.new
98
+ path.quadratic_curve_to 100,200,300,400
99
+ lambda { path.cubic_curve_to 500, 600, 700, 800 }.should raise_error
100
+ end
101
+ it 'should not raise an error if in short format and the previous command is of type CubicCurveTo' do
102
+ path = SubPath.new
103
+ path.cubic_curve_to 100,200,300,400,500,600
104
+ lambda { path.cubic_curve_to 500, 600, 700, 800 }.should_not raise_error
105
+ end
106
+ end
107
+ describe '#closed?' do
108
+ it 'should be true if the last direction in the directions list is of type ClosePath' do
109
+ path = SubPath.new
110
+ path.move_to 100, 300
111
+ path.line_to 243, 21
112
+ path.close_path
113
+ path.closed?.should == true
114
+ end
115
+ it 'should be false if the last direction in the directions list is of any other type or absent' do
116
+ path = SubPath.new
117
+ path.move_to 100, 300
118
+ path.line_to 234, 21
119
+ path.closed?.should == false
120
+ path2 = SubPath.new
121
+ path2.closed?.should == false
122
+ end
123
+ end
124
+ describe '#to_command' do
125
+ before :each do
126
+ @path = SubPath.new
127
+ @dir_1 = @path.move_to 100, 200
128
+ end
129
+ it 'should output the concatenation of all the subdirections if no two are the same in sequence' do
130
+ dir_2 = @path.horizontal_to -200
131
+ dir_3 = @path.quadratic_curve_to 342, -341.23, 405, 223
132
+ dir_4 = @path.line_to -342.002, 231.42
133
+ dir_5 = @path.close_path
134
+ @path.to_command.should == @dir_1.to_command << dir_2.to_command << dir_3.to_command << dir_4.to_command << dir_5.to_command
135
+ end
136
+ it 'should strip the command code if the previous code was the same as the present' do
137
+ dir_2 = @path.horizontal_to -200
138
+ dir_3 = @path.line_to -342.002, 231.42
139
+ dir_4 = @path.line_to -234, 502
140
+ @path.to_command.should == @dir_1.to_command << dir_2.to_command << dir_3.to_command << dir_4.to_command[1..-1]
141
+ end
142
+ it 'should not strip the command code if the previous code was the same as the present, but of different absoluteness' do
143
+ dir_2 = @path.horizontal_to -200
144
+ dir_3 = @path.line_to -342.002, 231.42
145
+ dir_4 = @path.line_to -234, 502, false
146
+ @path.to_command.should == @dir_1.to_command << dir_2.to_command << dir_3.to_command << dir_4.to_command
147
+ end
148
+ it 'should strip the command code if the previous code was a MoveTo and the current code is an absolute LineTo' do
149
+ dir_2 = @path.line_to -342.002, 231.42
150
+ dir_3 = @path.line_to -234, 502
151
+ @path.to_command.should == @dir_1.to_command << dir_2.to_command[1..-1] << dir_3.to_command[1..-1]
152
+ end
153
+ it 'should not strip the command code if the previous code was a MoveTo and the current code is a relative LineTo' do
154
+ dir_2 = @path.line_to -342.002, 231.42, false
155
+ dir_3 = @path.line_to -234, 502
156
+ @path.to_command.should == @dir_1.to_command << dir_2.to_command << dir_3.to_command
157
+ end
158
+ it 'should add leading whitespace if the first coordinate of the code-stripped direction is not negative' do
159
+ dir_2 = @path.horizontal_to -200
160
+ dir_3 = @path.line_to -342.002, 231.42
161
+ dir_4 = @path.line_to 234, 502
162
+ @path.to_command.should == @dir_1.to_command << dir_2.to_command << dir_3.to_command << dir_4.to_command[1..-1].insert(0,' ')
163
+ end
164
+ end
165
+ describe '#move_to' do
166
+ before :each do
167
+ @path = SubPath.new
168
+ end
169
+ context 'when the command list is empty' do
170
+ it 'should add a MoveTo command on to the directions list' do
171
+ this_move = @path.move_to(100,200)
172
+ @path.directions.should == [this_move]
173
+ end
174
+ it 'should return the newly created MoveTo command' do
175
+ @path.move_to(100,200).class.should == Directions::MoveTo
176
+ end
177
+ end
178
+ context 'when the command list is not empty' do
179
+ it 'does something' do
180
+ first_move = @path.move_to(200,400)
181
+ @path.move_to(100,200)
182
+ @path.directions.should == [first_move]
183
+ end
184
+ it 'should return nil' do
185
+ @path.move_to(200,400)
186
+ @path.move_to(100,200).nil?.should == true
187
+ end
188
+ end
189
+ end
190
+ describe '#directions' do
191
+ it 'should be able to access items via the bracket operator' do
192
+ SubPath.new.directions.respond_to?(:[]).should == true
193
+ end
194
+ end
195
+ end