Skip to content

Instantly share code, notes, and snippets.

@practicingruby
Created May 19, 2012 23:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save practicingruby/2732815 to your computer and use it in GitHub Desktop.
Save practicingruby/2732815 to your computer and use it in GitHub Desktop.
eval(DATA.read) # :trollface:
## USE VELLUM TO DESCRIBE A DRAWING IN THE ABSTRACT
drawing = Vellum::Drawing.new(300,400)
drawing.layer(:box) do |g|
g.rect(g.top_left, g.width, g.height)
end
drawing.layer(:x) do |g|
g.line(g.top_left, g.bottom_right)
.line(g.top_right, g.bottom_left)
end
drawing.layer(:cross) do |g|
g.line([g.width / 2, 0], [g.width / 2, g.height])
.line([0, g.height / 2], [g.width, g.height/2])
end
drawing.style(:x, :stroke_color => "ff0000")
drawing.style(:box, :line_width => 2,
:fill_color => "ffffcc")
drawing.style(:cross, :stroke_color => "00ff00")
## BEGIN PRAWN SPECIFIC CODE
require "prawn"
pdf = Prawn::Document.new
renderer = Vellum::Renderer.new
renderer.on(Object) do |shape, style|
pdf.stroke_color = style.fetch(:stroke_color, "000000")
pdf.fill_color = style.fetch(:fill_color, "ffffff")
pdf.line_width = style.fetch(:line_width, 1)
end
renderer.on(Vellum::Line) do |shape, style|
pdf.stroke_line(shape.p1, shape.p2)
end
renderer.on(Vellum::Rectangle) do |shape, style|
pdf.fill_and_stroke_rectangle(shape.point, shape.width, shape.height)
end
renderer.render(drawing)
pdf.render_file("foo.pdf")
__END__
## BEGIN VELLUM IMPLEMENTATION
require "forwardable"
module Vellum
class Box
def initialize(width, height)
@width = width
@height = height
end
attr_reader :width, :height
def top_left
[0, height]
end
def top_right
[width, height]
end
def bottom_left
[0, 0]
end
def bottom_right
[width, 0]
end
end
class Drawing
def initialize(width, height)
@dimensions = Box.new(width, height)
@layers = []
@styles = {}
end
attr_reader :dimensions, :layers
def layer(name)
new_layer = Layer.new(name)
yield Graphic.new(self, new_layer)
layers << new_layer
end
def style(name, params)
@styles[name] = params
end
def each
layers.each do |layer|
layer.elements.each do |shape|
yield shape, @styles.fetch(layer.name, {})
end
end
end
end
class Layer
def initialize(name)
@name = name
@elements = []
end
attr_reader :name, :elements
def <<(element)
elements << element
self
end
end
class Renderer
def initialize
@matchers = []
end
def on(pattern, &block)
@matchers << [pattern, block]
end
def render(document)
document.each do |shape, style|
@matchers.each do |pattern, action|
action.call(shape, style) if pattern === shape
end
end
end
private
attr_reader :matchers
end
class Graphic
extend Forwardable
delegate Box.instance_methods(false) => :dimensions
def initialize(drawing, layer)
@drawing = drawing
@layer = layer
end
attr_reader :drawing, :layer
def dimensions
@drawing.dimensions
end
def line(*a, &b)
layer << Line.new(*a, &b)
self
end
def rect(*a, &b)
layer << Rectangle.new(*a, &b)
self
end
end
Line = Struct.new(:p1, :p2)
Rectangle = Struct.new(:point, :width, :height)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment