sketch-in-ruby 0.0.1
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.
- data/.gitignore +6 -0
- data/Gemfile +7 -0
- data/README.markdown +86 -0
- data/Rakefile +28 -0
- data/lib/geometry/dsl/polyline.rb +107 -0
- data/lib/geometry/dsl/turtle.rb +64 -0
- data/lib/sketch.rb +180 -0
- data/lib/sketch/builder.rb +100 -0
- data/lib/sketch/builder/path.rb +16 -0
- data/lib/sketch/builder/polygon.rb +15 -0
- data/lib/sketch/builder/polyline.rb +51 -0
- data/lib/sketch/dsl.rb +56 -0
- data/lib/sketch/group.rb +38 -0
- data/lib/sketch/layout.rb +118 -0
- data/lib/sketch/point.rb +7 -0
- data/sketch-in-ruby.gemspec +21 -0
- data/test/geometry/dsl/polyline.rb +81 -0
- data/test/sketch.rb +189 -0
- data/test/sketch/builder.rb +167 -0
- data/test/sketch/builder/path.rb +13 -0
- data/test/sketch/builder/polygon.rb +12 -0
- data/test/sketch/builder/polyline.rb +12 -0
- data/test/sketch/dsl.rb +104 -0
- data/test/sketch/group.rb +23 -0
- data/test/sketch/layout.rb +167 -0
- data/test/sketch/point.rb +44 -0
- data/test/sketch/polygon.rb +42 -0
- metadata +100 -0
data/test/sketch.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'sketch'
|
3
|
+
|
4
|
+
describe Sketch do
|
5
|
+
Size = Geometry::Size
|
6
|
+
|
7
|
+
let(:sketch) { Sketch.new }
|
8
|
+
|
9
|
+
it "should create a Sketch object" do
|
10
|
+
sketch.must_be_kind_of Sketch
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a read only elements accessor" do
|
14
|
+
sketch.must_respond_to :elements
|
15
|
+
sketch.wont_respond_to :elements=
|
16
|
+
end
|
17
|
+
|
18
|
+
it "must have a push method that pushes an element" do
|
19
|
+
sketch.push Rectangle.new size:[5, 5]
|
20
|
+
sketch.elements.last.must_be_kind_of Rectangle
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must push a sketch with a transformation" do
|
24
|
+
sketch.push Sketch.new(), origin:[1,2]
|
25
|
+
sketch.elements.last.must_be_kind_of Sketch
|
26
|
+
sketch.elements.last.transformation.must_equal Geometry::Transformation.new(origin:[1,2])
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "parameters" do
|
30
|
+
it "must define custom parameters" do
|
31
|
+
Sketch.define_parameter(:a_parameter) { 42 }
|
32
|
+
Sketch.new.a_parameter.must_equal 42
|
33
|
+
end
|
34
|
+
|
35
|
+
it "must bequeath custom parameters to subclasses" do
|
36
|
+
Sketch.define_parameter(:a_parameter) { 42 }
|
37
|
+
Class.new(Sketch).new.must_respond_to(:a_parameter)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "must not allow access to parameters defined on a subclass" do
|
41
|
+
Sketch.define_parameter(:a_parameter) { 42 }
|
42
|
+
Class.new(Sketch).define_parameter(:b_parameter) { 24 }
|
43
|
+
Sketch.new.wont_respond_to :b_parameter
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have a circle command that makes a new circle from a center point and radius" do
|
48
|
+
circle = sketch.add_circle [1,2], 3
|
49
|
+
circle.must_be_kind_of Geometry::Circle
|
50
|
+
circle.center.must_equal Point[1,2]
|
51
|
+
circle.radius.must_equal 3
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have a point creation method" do
|
55
|
+
point = sketch.add_point(5,6)
|
56
|
+
point.must_be_kind_of Sketch::Point
|
57
|
+
point.x.must_equal 5
|
58
|
+
point.y.must_equal 6
|
59
|
+
end
|
60
|
+
|
61
|
+
it "have a line creation method" do
|
62
|
+
line = sketch.add_line([5,6], [7,8])
|
63
|
+
line.must_be_kind_of Sketch::Line
|
64
|
+
end
|
65
|
+
|
66
|
+
it "have a rectangle creation method" do
|
67
|
+
rectangle = sketch.add_rectangle size:[10, 20]
|
68
|
+
rectangle.must_be_kind_of Geometry::Rectangle
|
69
|
+
rectangle.points.must_equal [Point[0,0], Point[0,20], Point[10,20], Point[10,0]]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have a method for adding a square" do
|
73
|
+
square = sketch.add_square 10
|
74
|
+
square.must_be_kind_of Geometry::Square
|
75
|
+
square.width.must_equal 10
|
76
|
+
square.height.must_equal 10
|
77
|
+
square.center.must_equal Point[0,0]
|
78
|
+
square.points.must_equal [Point[-5,-5], Point[5,-5], Point[5,5], Point[-5,5]]
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "when constructed with a block" do
|
82
|
+
before do
|
83
|
+
@sketch = Sketch.new do
|
84
|
+
add_circle [1,2], 3
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should execute the block" do
|
89
|
+
circle = @sketch.elements.last
|
90
|
+
circle.must_be_kind_of Geometry::Circle
|
91
|
+
circle.center.must_equal Point[1,2]
|
92
|
+
circle.radius.must_equal 3
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "object creation" do
|
97
|
+
it "must create an Arc" do
|
98
|
+
arc = sketch.add_arc center:[1,2], radius:3, start:0, end:90
|
99
|
+
sketch.elements.last.must_be_kind_of Geometry::Arc
|
100
|
+
arc.center.must_equal Point[1,2]
|
101
|
+
arc.radius.must_equal 3
|
102
|
+
arc.start_angle.must_equal 0
|
103
|
+
arc.end_angle.must_equal 90
|
104
|
+
end
|
105
|
+
|
106
|
+
it "triangle" do
|
107
|
+
triangle = sketch.add_triangle [0,0], [1,0], [0,1]
|
108
|
+
sketch.elements.last.must_be_kind_of Geometry::Triangle
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "properties" do
|
113
|
+
subject { Sketch.new { add_circle [1,-2], 3; add_circle([-1,2], 3) } }
|
114
|
+
|
115
|
+
it "must have a bounds rectangle" do
|
116
|
+
subject.bounds.must_equal Rectangle.new(from:[-4,-5], to:[4,5])
|
117
|
+
end
|
118
|
+
|
119
|
+
it "must have an accessor for the first element" do
|
120
|
+
subject.first.must_be_instance_of(Geometry::Circle)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "must have an accessor for the last element" do
|
124
|
+
subject.last.must_be_instance_of(Geometry::Circle)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "must have a max property that returns the upper right point of the bounding rectangle" do
|
128
|
+
subject.max.must_equal Point[4,5]
|
129
|
+
end
|
130
|
+
|
131
|
+
it "must have a min property that returns the lower left point of the bounding rectangle" do
|
132
|
+
subject.min.must_equal Point[-4,-5]
|
133
|
+
end
|
134
|
+
|
135
|
+
it "must have a minmax property that returns the corners of the bounding rectangle" do
|
136
|
+
subject.minmax.must_equal [Point[-4,-5], Point[4,5]]
|
137
|
+
end
|
138
|
+
|
139
|
+
it "must have a size" do
|
140
|
+
subject.size.must_equal Size[8,10]
|
141
|
+
subject.size.must_be_instance_of(Size)
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "when the Sketch is empty" do
|
145
|
+
subject { Sketch.new }
|
146
|
+
|
147
|
+
it "max must return nil" do
|
148
|
+
subject.max.must_be_nil
|
149
|
+
end
|
150
|
+
|
151
|
+
it "min must return nil" do
|
152
|
+
subject.min.must_be_nil
|
153
|
+
end
|
154
|
+
|
155
|
+
it "minmax must return an array of nils" do
|
156
|
+
subject.minmax.each {|a| a.must_be_nil }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "when the Sketch is rotated" do
|
161
|
+
subject do
|
162
|
+
s = Sketch.new { add_rectangle center:[0, -1.5], size:[6.5, 50.5] }
|
163
|
+
s.transformation = Geometry::Transformation.new(angle:Math::PI/2)
|
164
|
+
s
|
165
|
+
end
|
166
|
+
|
167
|
+
it "must have a min property that returns the lower left point of the bounding rectangle" do
|
168
|
+
subject.min.x.must_be_close_to -23.75
|
169
|
+
subject.min.y.must_be_close_to -3.25
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "when the Sketch contains a group" do
|
175
|
+
subject { Sketch::Builder.new(Sketch.new).evaluate { translate [1,2] { circle [1,-2], 3; circle([-1,2], 3) } } }
|
176
|
+
|
177
|
+
it "must have a max property" do
|
178
|
+
subject.max.must_equal Point[5,7]
|
179
|
+
end
|
180
|
+
|
181
|
+
it "must have a min property" do
|
182
|
+
subject.min.must_equal Point[-3,-3]
|
183
|
+
end
|
184
|
+
|
185
|
+
it "must have a minmax property" do
|
186
|
+
subject.minmax.must_equal [Point[-3,-3], Point[5,7]]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry'
|
3
|
+
require 'sketch/builder'
|
4
|
+
|
5
|
+
describe Sketch::Builder do
|
6
|
+
Builder = Sketch::Builder
|
7
|
+
Rectangle = Geometry::Rectangle
|
8
|
+
|
9
|
+
subject { Builder.new }
|
10
|
+
|
11
|
+
describe "when initialized without a block" do
|
12
|
+
let(:builder) { Builder.new }
|
13
|
+
|
14
|
+
it "should create a new Sketch when initialized without a Sketch" do
|
15
|
+
builder.sketch.must_be_instance_of(Sketch)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should use the given sketch when initialized with an existing Sketch" do
|
19
|
+
sketch = Sketch.new
|
20
|
+
Builder.new(sketch).sketch.must_be_same_as(sketch)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must have a push method that pushes elements" do
|
24
|
+
builder.push Rectangle.new size:[5, 5]
|
25
|
+
builder.sketch.elements.last.must_be_kind_of Rectangle
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "command handlers" do
|
29
|
+
it "must recognize the rectangle command" do
|
30
|
+
builder.rectangle([1,2], [3,4]).must_be_instance_of(Rectangle)
|
31
|
+
builder.sketch.elements.last.must_be_kind_of Rectangle
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "when evaluating a block" do
|
36
|
+
describe "with simple geometry" do
|
37
|
+
before do
|
38
|
+
builder.evaluate do
|
39
|
+
square 5
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create the commanded elements" do
|
44
|
+
builder.sketch.elements.last.must_be_kind_of Geometry::Square
|
45
|
+
end
|
46
|
+
|
47
|
+
it "triangle" do
|
48
|
+
builder.evaluate { triangle [0,0], [1,0], [0,1] }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "that defines a parameter" do
|
53
|
+
before do
|
54
|
+
builder.evaluate do
|
55
|
+
let(:parameterA) { 42 }
|
56
|
+
circle [1,2], parameterA
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "must define the parameter" do
|
61
|
+
builder.sketch.parameterA.must_equal 42
|
62
|
+
end
|
63
|
+
|
64
|
+
it "must use the parameter" do
|
65
|
+
builder.sketch.elements.last.must_be_instance_of Geometry::Circle
|
66
|
+
builder.sketch.elements.last.radius.must_equal 42
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "with a path block" do
|
71
|
+
before do
|
72
|
+
builder.evaluate do
|
73
|
+
path do
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must add a Path object to the Sketch" do
|
79
|
+
builder.sketch.elements.last.must_be_instance_of Geometry::Path
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "when initialized with a block " do
|
86
|
+
let(:builder) {
|
87
|
+
Builder.new do
|
88
|
+
square 5
|
89
|
+
end
|
90
|
+
}
|
91
|
+
|
92
|
+
it "must evaluate the block" do
|
93
|
+
builder.sketch.elements.last.must_be_kind_of Geometry::Square
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "when adding a group" do
|
98
|
+
describe "without a block" do
|
99
|
+
before do
|
100
|
+
subject.group origin:[1,2,3]
|
101
|
+
end
|
102
|
+
|
103
|
+
it "must have a group element" do
|
104
|
+
subject.sketch.elements.first.must_be_kind_of Sketch::Group
|
105
|
+
subject.sketch.elements.first.translation.must_equal Point[1,2,3]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "with a block" do
|
110
|
+
before do
|
111
|
+
subject.group origin:[1,2,3] { circle diameter:1 }
|
112
|
+
end
|
113
|
+
|
114
|
+
it "must have a group element" do
|
115
|
+
subject.sketch.elements.first.must_be_kind_of Sketch::Group
|
116
|
+
end
|
117
|
+
|
118
|
+
it "must have the correct property values" do
|
119
|
+
subject.sketch.elements.first.translation.must_equal Point[1,2,3]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "when adding a translation" do
|
125
|
+
before do
|
126
|
+
subject.translate [1,2] { circle diameter:1 }
|
127
|
+
end
|
128
|
+
|
129
|
+
it "must have a group element" do
|
130
|
+
subject.sketch.elements.first.must_be_kind_of Sketch::Group
|
131
|
+
end
|
132
|
+
|
133
|
+
it "must have the correct property values" do
|
134
|
+
subject.sketch.elements.first.translation.must_equal Point[1,2]
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'must reject higher dimensions' do
|
138
|
+
-> { subject.translate [1,2,3] }.must_raise ArgumentError
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "when adding a nested translation" do
|
143
|
+
before do
|
144
|
+
subject.translate [1,2] do
|
145
|
+
translate [3,4] { circle diameter:2 }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
it "must have a group element" do
|
150
|
+
subject.sketch.elements.first.must_be_kind_of Sketch::Group
|
151
|
+
end
|
152
|
+
|
153
|
+
it "must have the correct property values" do
|
154
|
+
subject.sketch.elements.first.translation.must_equal Point[1,2]
|
155
|
+
end
|
156
|
+
|
157
|
+
it "must have a sub-group element" do
|
158
|
+
outer_group = subject.sketch.elements.first
|
159
|
+
outer_group.elements.first.must_be_kind_of Sketch::Group
|
160
|
+
end
|
161
|
+
|
162
|
+
it "must set the sub-group properties" do
|
163
|
+
outer_group = subject.sketch.elements.first
|
164
|
+
outer_group.elements.first.translation.must_equal Point[3,4]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'sketch/builder/path'
|
3
|
+
|
4
|
+
describe Sketch::Builder::Path do
|
5
|
+
Path = Sketch::Path
|
6
|
+
Point = Geometry::Point
|
7
|
+
|
8
|
+
let(:builder) { Sketch::Builder::Path.new }
|
9
|
+
|
10
|
+
it "must build a Path from a block" do
|
11
|
+
builder.evaluate {}.must_be_kind_of Path
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'sketch/builder/polygon'
|
3
|
+
|
4
|
+
describe Sketch do
|
5
|
+
let(:builder) { Sketch::Builder::Polygon.new }
|
6
|
+
|
7
|
+
it "build a polygon with a block" do
|
8
|
+
polygon = builder.evaluate do
|
9
|
+
end
|
10
|
+
assert_kind_of(Sketch::Polygon, polygon)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'sketch/builder/polyline'
|
3
|
+
|
4
|
+
describe Sketch::Builder::Polyline do
|
5
|
+
Polyline = Sketch::Polyline
|
6
|
+
|
7
|
+
let(:builder) { Sketch::Builder::Polyline.new }
|
8
|
+
|
9
|
+
it "must build a Polyline from a block" do
|
10
|
+
builder.evaluate {}.must_be_kind_of Polyline
|
11
|
+
end
|
12
|
+
end
|
data/test/sketch/dsl.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'sketch/dsl'
|
3
|
+
|
4
|
+
class Fake
|
5
|
+
attr_accessor :elements
|
6
|
+
|
7
|
+
include Sketch::DSL
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@elements = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def push(*args)
|
14
|
+
elements.push args.first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe Sketch::DSL do
|
19
|
+
Point = Geometry::Point
|
20
|
+
|
21
|
+
subject { Fake.new }
|
22
|
+
|
23
|
+
it "must have a first command that returns the first element" do
|
24
|
+
point = Geometry::Point[1,2]
|
25
|
+
subject.elements.push point
|
26
|
+
subject.first.must_be_same_as point
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must have a last command that returns the last element" do
|
30
|
+
point = Point[1,2]
|
31
|
+
subject.elements.push Point[3,4]
|
32
|
+
subject.elements.push point
|
33
|
+
subject.last.must_be_same_as point
|
34
|
+
end
|
35
|
+
|
36
|
+
it "must have a hexagon command" do
|
37
|
+
subject.hexagon center:[1,2], radius:5
|
38
|
+
subject.last.must_be_instance_of Geometry::RegularPolygon
|
39
|
+
subject.last.center.must_equal Point[1,2]
|
40
|
+
subject.last.edge_count.must_equal 6
|
41
|
+
subject.last.radius.must_equal 5
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'must have a path command that takes a list of points' do
|
45
|
+
subject.path [1,2], [2,3]
|
46
|
+
subject.last.must_be_kind_of Geometry::Path
|
47
|
+
subject.last.elements.count.must_equal 1
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'must have a path command that takes a block' do
|
51
|
+
subject.path do
|
52
|
+
start_at [0,0]
|
53
|
+
move_to [1,1]
|
54
|
+
end
|
55
|
+
subject.last.must_be_kind_of Geometry::Path
|
56
|
+
subject.last.elements.count.must_equal 1
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "when layout" do
|
60
|
+
describe "without spacing" do
|
61
|
+
it "must do a horizontal layout" do
|
62
|
+
subject.layout :horizontal do
|
63
|
+
rectangle from:[0,0], to:[5,5]
|
64
|
+
rectangle from:[0,0], to:[6,6]
|
65
|
+
end
|
66
|
+
|
67
|
+
group = subject.first
|
68
|
+
group.must_be_instance_of Sketch::Layout
|
69
|
+
|
70
|
+
group.first.must_be_kind_of Geometry::Rectangle
|
71
|
+
group.last.must_be_kind_of Sketch::Group
|
72
|
+
end
|
73
|
+
|
74
|
+
it "must do a vertical layout" do
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "with spacing" do
|
79
|
+
it "must do a horizontal layout" do
|
80
|
+
end
|
81
|
+
|
82
|
+
it "must do a vertical layout" do
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'must have a polygon command that takes a list of points' do
|
88
|
+
polygon = subject.polygon [0,0], [1,0], [1,1], [0,1]
|
89
|
+
polygon.must_be_kind_of Sketch::Polygon
|
90
|
+
subject.last.vertices.size.must_equal 4
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'must have a polygon command that takes a block' do
|
94
|
+
subject.polygon do
|
95
|
+
start_at [0,0]
|
96
|
+
move_to [1,0]
|
97
|
+
move_to [1,1]
|
98
|
+
move_to [0,1]
|
99
|
+
end
|
100
|
+
subject.last.must_be_kind_of Sketch::Polygon
|
101
|
+
subject.elements.size.must_equal 1
|
102
|
+
subject.last.vertices.size.must_equal 4
|
103
|
+
end
|
104
|
+
end
|