trtl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE.md +7 -0
- data/README.md +62 -0
- data/Rakefile +5 -0
- data/examples/example1.rb +14 -0
- data/examples/example2.rb +14 -0
- data/examples/example3.rb +21 -0
- data/examples/example4.rb +33 -0
- data/examples/example5.rb +12 -0
- data/examples/example6.rb +12 -0
- data/lib/trtl.rb +171 -0
- data/test/helper.rb +3 -0
- data/test/test_trtl.rb +64 -0
- data/trtl.gemspec +20 -0
- metadata +62 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2012 Peter Cooper
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Trtl - Simple Ruby Turtle Graphics
|
2
|
+
|
3
|
+
![example session](http://no.gd/p/trtl-20120708-034138.jpg)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
gem install trtl
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
Trtl is a simple turtle system inspired by Python's turtle.py. It provides
|
11
|
+
simple turtle drawing capabilities in Ruby, even if you're just at an IRb
|
12
|
+
prompt. It leans on Tk which is part of MRI 1.9's standard library so in theory it should
|
13
|
+
work 'out of the box' with most MRI 1.9 installs.
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
If Trtl detects you're in an IRb or Pry session, it'll automatically make turtle
|
18
|
+
methods available directly at the prompt. For example:
|
19
|
+
|
20
|
+
$ irb
|
21
|
+
> require 'trtl'
|
22
|
+
> forward 100
|
23
|
+
# At this point, a window appears with the turtle
|
24
|
+
|
25
|
+
If you wish to use Trtl from a regular Ruby script, you have a few options. You
|
26
|
+
can create a Trtl instance and use it directly:
|
27
|
+
|
28
|
+
require 'trtl'
|
29
|
+
t = Trtl.new
|
30
|
+
10.times { t.left(24); t.forward(30); t.ensure_drawn }
|
31
|
+
t.wait
|
32
|
+
|
33
|
+
You can use Trtl's `run` method to use it in a more interactive fashion:
|
34
|
+
|
35
|
+
Trtl.new.run { 10.times { left(24); forward(30); ensure_drawn } }
|
36
|
+
|
37
|
+
Or you can include InteractiveTurtle and get a similar effect as if you were in
|
38
|
+
IRb:
|
39
|
+
|
40
|
+
include InteractiveTurtle
|
41
|
+
10.times { left(24); forward(30) }
|
42
|
+
|
43
|
+
Note: Using InteractiveTurtle makes drawing slower as it ensures all graphics
|
44
|
+
are drawn after every action (as necessary for IRb use).
|
45
|
+
|
46
|
+
## Examples
|
47
|
+
|
48
|
+
The examples in the `examples` folder should be reasonably illustrative. If you
|
49
|
+
try any of them, try `example4.rb` - it renders an awesome looking tree.
|
50
|
+
|
51
|
+
![tree](http://no.gd/p/trtltree-20120708-035127.jpg)
|
52
|
+
|
53
|
+
## Credits
|
54
|
+
|
55
|
+
* turtle.py for inspiration
|
56
|
+
* Some of the examples taken from examples for an earlier Ruby turtle found at http://www.rubyquiz.com/quiz104.html
|
57
|
+
|
58
|
+
## Copyright and License
|
59
|
+
|
60
|
+
Copyright (c) 2012 Peter Cooper (other than minor parts of some samples.)
|
61
|
+
|
62
|
+
MIT licensed. See LICENSE.md
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../lib/trtl'
|
2
|
+
|
3
|
+
# Example of using Trtl in a 'simple' interactive fashion
|
4
|
+
|
5
|
+
# In irb or pry this isn't needed as InteractiveTurtle will be
|
6
|
+
# included by default.
|
7
|
+
include InteractiveTurtle
|
8
|
+
|
9
|
+
10.times do
|
10
|
+
left(24)
|
11
|
+
forward(30)
|
12
|
+
end
|
13
|
+
|
14
|
+
wait
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative '../lib/trtl'
|
2
|
+
|
3
|
+
include InteractiveTurtle
|
4
|
+
|
5
|
+
# Example below taken from Ruby quiz turtle_graphics archive
|
6
|
+
# http://www.rubyquiz.com/quiz104.html
|
7
|
+
|
8
|
+
# BYZANTIUM
|
9
|
+
|
10
|
+
def byzantium(r, n)
|
11
|
+
return if n < 1
|
12
|
+
fd r; rt 135
|
13
|
+
4.times {
|
14
|
+
pd; fd 2 * r * Math.sin(45 * DEG); pu
|
15
|
+
byzantium(r / 2, n - 1)
|
16
|
+
rt 90
|
17
|
+
}
|
18
|
+
lt 135; bk r
|
19
|
+
end
|
20
|
+
|
21
|
+
byzantium(100, 4)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../lib/trtl'
|
2
|
+
|
3
|
+
# Example below adapted from Ruby quiz turtle_graphics archive
|
4
|
+
# http://www.rubyquiz.com/quiz104.html
|
5
|
+
|
6
|
+
# TREE
|
7
|
+
|
8
|
+
Trtl.new(:width => 2, :color => 'brown').run do
|
9
|
+
def tree(_size)
|
10
|
+
if _size < 10
|
11
|
+
forward _size; back _size; return
|
12
|
+
end
|
13
|
+
color 'brown'
|
14
|
+
forward _size / 3
|
15
|
+
color %w{green darkgreen darkolivegreen}.sample
|
16
|
+
left 30; tree _size * 2 / 3; right 30
|
17
|
+
forward _size / 6
|
18
|
+
right 25; tree _size / 2; left 25
|
19
|
+
forward _size / 3
|
20
|
+
width rand(2) + 1
|
21
|
+
right 25; tree _size / 2; left 25
|
22
|
+
forward _size / 6
|
23
|
+
back _size
|
24
|
+
ensure_drawn
|
25
|
+
end
|
26
|
+
|
27
|
+
left 90
|
28
|
+
back 180
|
29
|
+
pen_down
|
30
|
+
tree 300.0
|
31
|
+
|
32
|
+
wait
|
33
|
+
end
|
data/lib/trtl.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'tk'
|
2
|
+
|
3
|
+
class Trtl
|
4
|
+
VERSION = "0.0.1"
|
5
|
+
|
6
|
+
CANVAS_WIDTH = 800
|
7
|
+
CANVAS_HEIGHT = 600
|
8
|
+
HOME_X = CANVAS_WIDTH / 2
|
9
|
+
HOME_Y = CANVAS_HEIGHT / 2
|
10
|
+
COLORS = %w{red blue green white cyan pink yellow}
|
11
|
+
DEG = Math::PI / 180.0
|
12
|
+
|
13
|
+
attr_accessor :heading, :x, :y
|
14
|
+
attr_writer :color, :width
|
15
|
+
attr_reader :canvas
|
16
|
+
|
17
|
+
def initialize(options = {})
|
18
|
+
@color = options[:color] || COLORS.sample
|
19
|
+
@interactive = options[:interactive]
|
20
|
+
@canvas = options[:canvas] || self.class.canvas
|
21
|
+
@width = options[:width] || 1
|
22
|
+
@drawing = true
|
23
|
+
home
|
24
|
+
draw
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.canvas
|
28
|
+
return @canvas if @canvas
|
29
|
+
|
30
|
+
root = TkRoot.new(:title => 'trtl', :minsize => [CANVAS_WIDTH, CANVAS_HEIGHT])
|
31
|
+
@canvas = TkCanvas.new(root, :bg => 'black', :highlightthickness => 0, :width => CANVAS_WIDTH, :height => CANVAS_HEIGHT)
|
32
|
+
@canvas.pack(:fill => 'both', :expand => 1)
|
33
|
+
@canvas
|
34
|
+
end
|
35
|
+
|
36
|
+
def pen_up
|
37
|
+
@drawing = false
|
38
|
+
end
|
39
|
+
|
40
|
+
def pen_down
|
41
|
+
@drawing = true
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_drawing?
|
45
|
+
@drawing
|
46
|
+
end
|
47
|
+
|
48
|
+
def color(color)
|
49
|
+
@color = color.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def width(width)
|
53
|
+
@width = width
|
54
|
+
end
|
55
|
+
|
56
|
+
def forward(amount = 20)
|
57
|
+
new_x = (@x + dx * amount)
|
58
|
+
new_y = (@y + dy * amount)
|
59
|
+
move(new_x, new_y)
|
60
|
+
end
|
61
|
+
|
62
|
+
def back(amount = 20)
|
63
|
+
new_x = (@x - dx * amount)
|
64
|
+
new_y = (@y - dy * amount)
|
65
|
+
move(new_x, new_y)
|
66
|
+
end
|
67
|
+
|
68
|
+
def move(new_x, new_y)
|
69
|
+
TkcLine.new(canvas, @x, @y, new_x, new_y, :width => @width, :fill => @color) if @drawing
|
70
|
+
@x, @y = new_x, new_y
|
71
|
+
draw
|
72
|
+
end
|
73
|
+
|
74
|
+
def right(offset)
|
75
|
+
@heading = (@heading + offset) % 360
|
76
|
+
draw
|
77
|
+
end
|
78
|
+
|
79
|
+
def left(offset)
|
80
|
+
@heading = (@heading - offset) % 360
|
81
|
+
draw
|
82
|
+
end
|
83
|
+
|
84
|
+
def dot(size = nil)
|
85
|
+
size ||= [@width + 4, @width * 2].max
|
86
|
+
TkcOval.new(canvas, @x - size / 2, @y - size / 2, @x + size / 2, @y + size / 2, :fill => @color, :outline => @color)
|
87
|
+
end
|
88
|
+
|
89
|
+
# TODO / TOFIX: This is horribly wrong with the fewer steps due to circumference varying ;-)
|
90
|
+
def circle(radius, extent = 360, steps = 360)
|
91
|
+
circumference = (Math::PI * 2 * radius) * (extent / 360.0)
|
92
|
+
steps.times do
|
93
|
+
left extent / steps.to_f
|
94
|
+
forward circumference / steps.to_f
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def position
|
99
|
+
[@x, @y]
|
100
|
+
end
|
101
|
+
|
102
|
+
def home
|
103
|
+
@x = HOME_X
|
104
|
+
@y = HOME_Y
|
105
|
+
@heading = 0
|
106
|
+
draw
|
107
|
+
end
|
108
|
+
|
109
|
+
def sleep(time = 100000)
|
110
|
+
Tk.sleep(time)
|
111
|
+
end
|
112
|
+
|
113
|
+
def ensure_drawn
|
114
|
+
sleep 30
|
115
|
+
end
|
116
|
+
|
117
|
+
def wait
|
118
|
+
ensure_drawn and gets
|
119
|
+
end
|
120
|
+
|
121
|
+
alias :run :instance_eval
|
122
|
+
|
123
|
+
# Compatibility aliases (with turtle.py and KidsRuby primarily)
|
124
|
+
alias :fd :forward
|
125
|
+
alias :bk :back
|
126
|
+
alias :rt :right
|
127
|
+
alias :lt :left
|
128
|
+
alias :pu :pen_up
|
129
|
+
alias :pd :pen_down
|
130
|
+
alias :penup :pen_up
|
131
|
+
alias :pendown :pen_down
|
132
|
+
alias :up :pen_up
|
133
|
+
alias :down :pen_down
|
134
|
+
alias :turnright :right
|
135
|
+
alias :turnleft :left
|
136
|
+
alias :backward :back
|
137
|
+
alias :pencolor :color
|
138
|
+
alias :goto :move
|
139
|
+
alias :setpos :move
|
140
|
+
alias :setposition :move
|
141
|
+
alias :pos :position
|
142
|
+
|
143
|
+
private
|
144
|
+
def dx
|
145
|
+
Math.cos(@heading * DEG)
|
146
|
+
end
|
147
|
+
|
148
|
+
def dy
|
149
|
+
Math.sin(@heading * DEG)
|
150
|
+
end
|
151
|
+
|
152
|
+
def draw
|
153
|
+
canvas.delete(@turtle_line) if @turtle_line
|
154
|
+
@turtle_line = TkcLine.new(canvas, @x, @y, @x + dx * 5 , @y + dy * 5, :arrow => 'last', :width => 10, :fill => @color)
|
155
|
+
# Can probably just use ensure_drawn actually..
|
156
|
+
TkTimer.new(60, 1) { Tk.update }.start.wait if @interactive
|
157
|
+
true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
module InteractiveTurtle
|
162
|
+
DEG = Math::PI / 180.0
|
163
|
+
|
164
|
+
Trtl.instance_methods(false).each do |meth|
|
165
|
+
define_method meth do |*args, &p|
|
166
|
+
(@turtle ||= ::Trtl.new(:interactive => true)).send(meth, *args, &p)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
include InteractiveTurtle if %w{irb pry}.include?($0)
|
data/test/helper.rb
ADDED
data/test/test_trtl.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
# Note: Only very simple high level tests here. Just stretching
|
4
|
+
# some of the public API. One day I may care to stub out Tk ;-)
|
5
|
+
|
6
|
+
describe Trtl do
|
7
|
+
before do
|
8
|
+
@trtl = Trtl.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "gets a default canvas when none is provided" do
|
12
|
+
@trtl.canvas.must_be_instance_of TkCanvas
|
13
|
+
end
|
14
|
+
|
15
|
+
it "has pen down by default" do
|
16
|
+
@trtl.is_drawing?.must_equal true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can have pen moved up" do
|
20
|
+
@trtl.pen_up
|
21
|
+
@trtl.is_drawing?.must_equal false
|
22
|
+
end
|
23
|
+
|
24
|
+
it "has default X and Y set" do
|
25
|
+
@trtl.x.must_equal Trtl::CANVAS_WIDTH / 2
|
26
|
+
@trtl.y.must_equal Trtl::CANVAS_HEIGHT / 2
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can report its position" do
|
30
|
+
@trtl.position.must_equal [@trtl.x, @trtl.y]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can rotate and change heading" do
|
34
|
+
@trtl.left 20
|
35
|
+
@trtl.heading.must_equal 340
|
36
|
+
@trtl.right 40
|
37
|
+
@trtl.heading.must_equal 20
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can move in straight lines" do
|
41
|
+
start_x, start_y = @trtl.position
|
42
|
+
@trtl.heading = 0
|
43
|
+
@trtl.forward 50
|
44
|
+
@trtl.x.must_equal start_x + 50
|
45
|
+
@trtl.heading = 90
|
46
|
+
@trtl.forward 50
|
47
|
+
@trtl.y.must_equal start_y + 50
|
48
|
+
@trtl.back 50
|
49
|
+
@trtl.y.must_equal start_y
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can move at angles" do
|
53
|
+
start_x, start_y = @trtl.position
|
54
|
+
@trtl.heading = 45
|
55
|
+
@trtl.forward 100
|
56
|
+
@trtl.x.must_be_close_to start_x + 100 / Math.sqrt(2)
|
57
|
+
@trtl.y.must_be_close_to start_y + 100 / Math.sqrt(2)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "can be moved absolutely" do
|
61
|
+
@trtl.move(310, 201)
|
62
|
+
@trtl.position.must_equal [310, 201]
|
63
|
+
end
|
64
|
+
end
|
data/trtl.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "trtl"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "trtl"
|
7
|
+
s.version = Trtl::VERSION
|
8
|
+
s.authors = ["Peter Cooper"]
|
9
|
+
s.email = ["git@peterc.org"]
|
10
|
+
s.homepage = "https://github.com/peterc/trtl"
|
11
|
+
s.summary = %q{Ruby turtle graphics (ideal for use from IRb)}
|
12
|
+
s.description = %q{A Logo / turtle.py style turtle graphics system for Ruby}
|
13
|
+
|
14
|
+
s.rubyforge_project = "trtl"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trtl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Peter Cooper
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-08 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A Logo / turtle.py style turtle graphics system for Ruby
|
15
|
+
email:
|
16
|
+
- git@peterc.org
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE.md
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- examples/example1.rb
|
27
|
+
- examples/example2.rb
|
28
|
+
- examples/example3.rb
|
29
|
+
- examples/example4.rb
|
30
|
+
- examples/example5.rb
|
31
|
+
- examples/example6.rb
|
32
|
+
- lib/trtl.rb
|
33
|
+
- test/helper.rb
|
34
|
+
- test/test_trtl.rb
|
35
|
+
- trtl.gemspec
|
36
|
+
homepage: https://github.com/peterc/trtl
|
37
|
+
licenses: []
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project: trtl
|
56
|
+
rubygems_version: 1.8.24
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Ruby turtle graphics (ideal for use from IRb)
|
60
|
+
test_files:
|
61
|
+
- test/helper.rb
|
62
|
+
- test/test_trtl.rb
|