XRVG base types extension

XRVG reuses and extends some Ruby base classes. In particular, it largely extends the Range class, to make it a central part of the toolkit.

General syntaxic sugar

XRVG adds several syntaxic sugar rules to Ruby:

A typical XRVG script then looks as follows:

require 'xrvg'
include XRVG

render = SVGRender[ :filename, "palette_circle.svg", :background, "white" ]

palette  = Palette[ :colorlist, [  0.0, Color.black,  1.0 ,  Color.blue] ]
SyncS[Circle[], palette, (0.1..0.02).random()].samples(25) do |point, color, radius|
  render.add( Circle[ :center, point, :radius, radius ], Style[ :fill, color ])
end

render.end

Range class extensions

Design considerations

In Ruby, a Range object represents a FINITE set of ordered values, "ranging" from one boundary to another, without hole. You can define for example integer ranges, character ranges, or more generally ranges of everything that can be ordered and from which a "next" element can be computed (to make sense of the "no hole" property). You can by extension define floats range, providing the definition of the "successor" operation.

By contrast, XRVG considers a float range as a CONTINUOUS range of float values between two included boundaries, corresponding to the mathematical definition of a (closed) continuous interval of real values. Ideally, XRVG should have defined another class for this purpose, but to make available the quite useful (a..b) notation, it has been preferred to extend Range class applicability (against coherency :-(.

Range's extension is realized through two modules :

Consequences

We are not going to extensively describe Samplable and Splittable modules (report to design page for further insights). The purpose here is just to highlight some practical features added by these modules on the Range class.

require 'xrvg'
include XRVG

# Samplable module
(1.0..2.0).sample(0.5);      #=> 1.5
(1.0..2.0).samples( 3 );     #=> [1.0, 1.5, 2.0]
(1.0..2.0).mean;             #=> 1.5; equiv to sample(0.5)
(1.0..2.0).middle;           #=> alias for previous
(1.0..2.0).rand;             #=> random value in range
(1.0..2.0).rand( 2 );        #=> [rand1, rand2] in range
(1.0..2.0).complement(1.2);  #=> 1.8
(1.0..2.0).abscissa(1.2);    #=> 0.2; inverse of sample

# Splittable module
(1.0..2.0).split(0.2,0.3);    #=> (1.2..1.3)
(1.0..2.0).splits( 2 );       #=> [(1.0..1.5),(1.5..2.0)]

Additional methods

Just to highlight some other features you may find useful

require 'xrvg'
include XRVG

Range.O;                   #=> (0.0..1.0)
Range.Angle;               #=> (0.0..2*Math::PI)
(1.0..2.0).reverse;        #=> (2.0..1.0)
(1.0..2.0).sym;            #=> (0.0..2.0)
(1.0..2.0).symend;         #=> (1.0..3.0)
(1.0..2.0).size;           #=> 1.0
(1.0..2.0).translate(0.3); #=> (1.3..2.3)

Array class extensions

Ruby Array class has also been extended for XRVG to provide "advanced" iterator methods

Standard Ruby Array can be augmented by the Enumerable module. When activated, this feature enables the use of the .enum_slice and .enum_cons methods, to enumerate sublists from an enumerable object.

To provide a more intuitive syntax, XRVG defines a new interface on these two methods, with the .foreach and .uplets operators. In particular, these operators allow the implicit declaration of the size of the iterated sublist, by the arity of a block.

require 'xrvg'
include XRVG

render = SVGRender[ :filename, "foreach.svg", :background, "white" ]
Circle[].samples(10).foreach do |p1,p2|
  render.add( Line[ :points, [p1,p2] ], Style[ :stroke, "black", :strokewidth, 0.1 ] )
  render.add( Circle[:center, p1, :radius, 0.1], Style[ :fill, Color.red ] )
  render.add( Circle[:center, p2, :radius, 0.2], Style[ :fill, Color.blue ] )
end
render.end

require 'xrvg'
include XRVG

render = SVGRender[ :filename, "uplets.svg", :background, "white" ]
Circle[].samples(10).uplets do |p1,p2|
  render.add( Line[ :points, [p1,p2]], Style[ :stroke, "black", :strokewidth, 0.1 ] )
  render.add( Circle[:center, p1, :radius, 0.1], Style[ :fill, Color.red ] )
  render.add( Circle[:center, p2, :radius, 0.2], Style[ :fill, Color.blue ] )
end
render.end

Please report to the reference page for further insights.