Farmer Ball (Ball Farm, on Ball Road) built Honeymoon House for his children. He thought they might enjoy some privacy as newlyweds. (Not on Ball Road, Honeymoon House is still just a short walk from the farm.)

Look closely at this charming home and you see something unusual. Clearly a bungalow, it features the hipped roof and hipped dormer that would later become typical of the Craftsman four-square. I strongly suspect that this home was builder-designed. It predates the Craftsman period by ten years!

Honeymoon House, Warwick, NY, 1895.

Honeymoon House, built by Farmer Ball for his children.

Edges to Rubies The Complete SketchUp Tutorial


Hello, World!, chapter 11 icon

Chapter 11—Introduction to Ruby Programming

Why Write Rubies?

The basic idea is simple. You write a little program that automates some portion of your work. From then on, when you meet the same task again, you just run your little program. That portion of your work is gone.

In this half of the book, we'll create programs that will teach you enough to build a complete, Craftsman-style (or any other style) carriage house. Those who want to add Ruby power can stop after Chapter 17. (The final three chapters are for those who want to add fancy WebDialog interfaces to their programs.)

Late in this chapter you'll meet SketchTalk. Much more on this at the end of the chapter. For now, here's the idea:

Building a SketchTalk Stairway

  1. Model a Riser
  2. Model the Tread
  3. Add a Baluster
  4. Add Another Baluster
  5. Create a "Step" Component
  6. Move/Copy Up Rise, Out Run, 14x
  7. Add the Banister

Each one of those model actions is a single SketchTalk command. Your entire stairway will be built by a seven-line Ruby! (P.S. Oops. I forgot that you need to select everything before you make the component. Make that eight lines.) Here's the code for selecting everything and turning it into a component named "step":

all
g 'step'

Do you think you could write two lines as complex as those? OK, I'm kidding. Making things dead simple is a major goal in Ruby programming.

And if you've hung around the Sketchucation forums, you know that many Ruby authors share their Rubies—sometimes for money, often for free—with others. Some have become famous within the SketchUp community for their Ruby brilliance. Your tutor is hoping to launch a few more Ruby stars.

Before we get going, there are some administrative matters to handle. With these out of the way we'll install a Ruby and then start programming.

Three Classes of Readers

Some of you are new to programming. Some of you are programmers ranging from minimally skilled to aces, but you don't know the Ruby language. A few of you are Ruby programmers who want to master the SketchUp Ruby API. I want to optimize the use of your time for all of you. Here's how.

Text, such as this, is for everyone. This is where we'll cover the SketchUp Ruby API.

Topic: API

This is a programming beginners' section. If you've done some programming, just look at the topic. If you know that API is short for Application Program Interface, and you know what that means, skip the section.

If you are new to programming, an API is a defined set of routines that your code can use to take advantage of a product such as SketchUp. Let's say you've drawn a face and given that face the name "f". You want to PushPull it up eight feet. Here's the API you'd use:

f.pushpull 96
That will not be on the quiz. Just as in manual SketchingUp, you'll pushpull often in your Rubies.

Coders: Ruby is case-sensitive.

This is a coder's section. If you are a programmer, but don't know Ruby, the first paragraph (not this one, the one above) will state the point. If you understand the first paragraph, you can skip the rest of the section.

For non-programmers, in a case-sensitive language "foo", "Foo" and "FOO" are three entirely different things. In a case-insensitive language, those three are all the same. On a PC, for instance, those are three ways of getting to the same file. On a Mac, those are three different file names.

Throughout this book I've named the command PushPull to remind you of the keyboard shortcut. Since Ruby is case-sensitive, you can't say:

f.PushPull # this is an error!
Topic: Tim Toady

Some experienced coders love Tim. Some experienced coders heartily dislike Tim.

Who is this controversial fellow? Actually, "Tim Toady" is the pronunciation for the acronym "TMTOWTDI". That comes from the Perl programming language and it stands for There's More Than One Way To Do It. "It", a pronoun without an antecedent, is like the geek favorite "foo." It stands for nothing in particular, everything in general. Ruby, which was designed to be a better Perl, usually has lots of ways to do "it".

The anti-Tim camp has its center in the Python programming language (named after the British comedy troupe, Monty Python). They say, "There should be one, obvious way to do it."

In my blog I have a pet python named "Monty." Monty promises to have a big hug for Tim if they meet. You don't want a big hug from Monty.

Tim Toady
# In a block like this I'll show Tim Toady alternatives.
# Programming beginners can skip these blocks. They won't help you get 
# past the beginner stage.

=begin
This is an alternative form of comment.

If you want to read Rubies written by others, you will want to
understand the alternatives. The loop style I'll teach is less
popular than another, Ruby-only style, for example.
=end
Topic: Comments

If you know what comments are, skip this block!

Comments are text placed in a computer program that is ignored by the computer. It is written by the programmer for the benefit of those who come to the program later. (Remember when you program that you may be the person who comes to the program later. Will you remember what you were thinking a week later? A month later? A year later?)

The Tim Toady block above shows two comment styles. You can use the "#" character to enter a comment. It may start the line, or it may follow code:

# Time to pull up the walls
w.pushpull 96 # 96 inches is 8 feet, US standard ceiling height
In Ruby you can also use "=begin" and "=end" as comment delimiters. They must be at the left edge of the comment block.
=begin
This is a block
comment.
=end

Let's summarize this section. Plain text is for everyone.

Topic: Skip the section if you understand the topic.
Coders: Read the first paragraph.

If it makes sense, skip the rest.

Tim Toady:

Read it if you want to read other authors' Rubies.

Installing Rubies

Have you installed Rubies? Do you know where your Plugins directory is? You can skip to the next section.

When SketchUp starts, it runs all the Rubies in your Plugins directory. It recognizes Rubies because their files end with ".rb" or some other, "I'm a Ruby program!" extension. The Plugins directory depends on your SketchUp version and whether you have a Mac or a PC. With either, you can find the Plugins directory this way.

Entering a command in the Ruby Console.  

Open your Ruby Console (Window/Ruby Console). In the white input area, type exactly what you see to the left. (Remember, Ruby is case-sensitive. "SketchUp" won't work. It must be "Sketchup".)

Response from the Ruby Console.  

After you press Enter, you will see something like this.

The first line echoes your input. The second line is the address of your Plugins directory. (The one in Figure 11-2 is the address of your Plugins directory if you are running Sketchup 7 on a PC. The one in your Ruby Console is the one you want.)

Now you need a Ruby to plug in. Copy this text:

# file_new.rb - start my way!
# Copyright 2009, Martin Rinehart

# Not licensed: 
#	remove copyright notice; 
# 	use in "how to program ..." material.
# Licensed: everything else.

require 'sketchup'

def send_actions()
	Sketchup.file_new() 
	Sketchup.send_action( 'selectSelectionTool:' )
end # of send_actions()

unless file_loaded?( "file_new.rb" )
	UI.menu("Plugins").add_item( 'New File ' ) { send_actions() }
	send_actions()
	Sketchup.send_action( 'showRubyPanel:' )
	file_loaded( "file_new.rb" )
end
Shortly I'm going to tell you to type in the code, not copy it. Copying is fine here. There's a lot that needs to be explained here, but this is not the place. We'll get there.

This Ruby is short, but not simple. It replaces the Line tool with the Selection tool when SketchUp starts up and after File/New. (Actually, you have to assign keyboard shortcut "N" to "New File" in the Plugins menu. Then tap "N" to get File/New followed by Tools/Select. Back to the start of Chapter 10 if you've forgotten how to assign keyboard shortcuts.)

After you copy the code, open your text editor and paste it into a blank page. Save this into your Plugins directory named "file_new.rb".

Close Sketchup and restart. (Remember, SketchUp loads all the ".rb" files when it starts.) You should see the Selection tool's arrow cursor. Click the Plugins menu item and you'll see "New File" as one of the menu choices. As SketchUp starts in File/New state, it will do nothing if you click it. Draw a box and then click Plugins/File New.

Suppose you liked the Line tool default choice. How do you uninstall a Ruby? Simple. Go to your Plugins directory and delete it. Note: a more complex Ruby, lets say "foo.rb" might have other support files. If the author got it right, you will have a "foo" subdirectory under Plugins where all the support files live. If you see a "foo" subdirectory, delete it when you delete "foo.rb".

You now know enough to install plugins. Go to Smustard.com (think about the name) and browse. Find a free one that looks interesting, download and install it. When you come back, we'll do our first Ruby programming.

Hello, World!

Programming used to be a lot more complicated than it is today. A programmer meeting a new language was challenged just to get the computer to say "Hello, World!" Today that can be quite simple, but it's still a good place to start.

The SketchUp command to put a text string to the console is "puts". Back to your Ruby Console and in the white input area type:

puts "Hello, World!"

Our first Hello, World!  

You should get a result like this.
The Console echoes your input. Then, in response, it puts the string you supplied in the console. Then it says "nil".

Coders: The Ruby keyword "nil" means "no value." It is returned by functions that don't return values, such as puts and it is the value of an uninitialized variable.

Topic: Constants

There are quite a lot of new concepts here. You typed "Hello, World!" with the quotation marks. That's called a "string constant." The value is actually the part between quotes. The quotes tell Ruby "string starts here" and later, "string ends here." They are called "delimiters." Note that the quotes disappear when your string is "puts" to the console.

There are other types of constants. The most common are numbers such as 2 or 3.14159265358979.

Coders:
The single- and double-quoted strings are not the same!

String substitutions via escaped characters are not performed within single-quoted strings. '\n' is not a newline. Within double quotes, "\n" is the symbol for a newline character.

Within single quotes there are two escaped characters: '\'' and '\\' (single quote and backslash).

Within double quotes there are many escaped characters. They start with the ones found in the C family tree:

Tim Toady: There are lots of other ways to write string constants in Ruby. Many of them take this form:
%q/this is a single-quoted string/
%Q/this is a double-quoted string/
%/this is short-hand for a double-quoted string/
%q!you can use any delimiter you want!
%Q[parens and brackets match in the regular fashion]

I almost never use these forms with one exception: if your string will include lots of double-quote and backslash characters these are handy as you don't escape these two characters.

Topic: Functions

A function is a tiny program. Typically you give it some value or values and it gives you back another value. Sketchup.find_support_file "Plugins" is a call to a function named Sketchup.find_support_file and a value, the string constant "Plugins". It returns a string such as C:/Program .... Other functions, such as "puts" are called to do something (write to a file, for example). If the function does something that does not return a value, "nil" or nothing, is the return value.

OK, that said "Hello, World!". We've seen that the console is alive and well and will do what we tell it to do, provided we use good Ruby to tell it what to do. Talking with a console was programming until late last century. Today we have better alternatives.
Topic: UI

UI is short for User Interface. It is the way your computer program communicates with a person using your computer program. Modern UI work—including windows, multiple fonts, mice and the other things you think of when you think of using your computer—was invented at Xerox's Palo Alto Research Center, Xerox PARC. Xerox did not know what to do with it.

In 1978, Steve Jobs, then Apple CEO, saw it and was blown away. He had seen the future. The Apple Lisa (a 1983 flop) and Macintosh (a 1984- enduring success) were not far behind. Microsoft saw Apple's work and, detouring through an ill-fated partnership with IBM, created Windows. Windows 3.0, the first successful version, was released in 1990.

Let's say "Hello, World!" but from a 21st century UI. We'll need to create a window, with facilities to move the window around the screen, spots that will respond to mouse clicks and the text "Hello, World!" should be in the window. Complicated stuff!

A modern Hello, World!  

Fortunately, the complications have all been worked out by others. You need to do this.
That's right, you use the UI.messagebox function to put a string constant up on the screen in a contemporary window. Grab the title bar and drag it around the screen. When you're ready to write your first Ruby, close it and rejoin us.

Ruby Programming

A "real" program is one that lives in a file. You can execute the program by "running" the file. Let's write our first program to see what this feels like. For starters, we'll need a directory where we can store our Ruby files. On my machine, C:\r\ holds Ruby programs. Make something that suits you on your machine. (Whatever you name it, make it easy to type. You'll be typing it a lot!)

Coders: First, you'll need a text editor that knows Ruby.

A word processor writes lots of things other than what you type into its files. That won't work at all.

On the PC, many SketchUp Ruby programmers use Notepad++. It's free and worth far more.

Topic: ++ (increment) Operator

Made popular by the "C" programming language, the ++ operator increments (adds one to) a counter.

count = 0
count++ # count now equals 1
count++ # 2 ...
The "C++" language was cleverly named. It added object-oriented programming capability to the C language. Therefore it was C made better. Since then any number of people have used "foo++" to suggest an improved "foo".
Notepad++ is much too modestly named. It's a real programming editor that supports programming in lots of languages, including Ruby. Google for a download location in your country.

I know you want to write your first Ruby program. Don't press on using some piece of junk editor. Take the time now to get a real editor and begin learning how to use it. This is a small investment with a huge return.

Here's the entire program I want you to write. (Warning: copying the code is certainly possible. But you won't learn programming. You need to actually transfer the code through your fingers into your editor to learn to program. Programming is typing code.)

# /r/hw1.rb - our first Ruby program

require 'sketchup'

UI.messagebox( "Hello, World!" )

# end of /r/hw1.rb
The first and fourth lines (when I say fourth line, the count does not include the blank lines) are comments that specify the start and end of the file. They let you check when a previously running program fails. When your car stops, the first thing to check is the gas. When your code stops, first check that you still have the full file.

Note that in the comment I've used the forward slash, which won't work in Windows. It will work in Ruby, which makes the appropriate correction if you are using Windows.

Coders: In Ruby you load or require supporting files.

Loading means actually reading from disk into memory. Requiring tells Ruby to load only if the file has not already been loaded.

The second line loads the 'sketchup.rb' file unless it has already been loaded. (You can skip the ".rb" extension for require, but not for load. Don't ask because I don't know.)

The third line is one you've already seen, but with added parentheses. Passing a string constant or other value(s) to a function is done this way in every language I've used, except Ruby. Many times, but not all, Ruby will warn you that using parentheses is good practice to be sure your code is compatible with future versions. From now on, except in SketchTalk, I'll use parentheses.

OK, you've typed those lines into your own editor and saved the result as "hw1.rb". It's in the comment so I won't have to keep repeating where the file gets saved, right?

Running a Ruby program from the Ruby Console  

How do you run the program? The answer is on the left.
Again, try it out. Drag it around. Close it. Congratulations! You've written a SketchUp Ruby plugin. (Sure. It's useless. But as your tutor, I don't think it's useless. I think you have begun the journey.)

Topic: Imperative Programming Paradigm

Really big words. Really small topic.

There are lots of ways to write programs. A collection of related programming techniques is called a "programming paradigm." In "imperative programming" your program is a series of commands to the computer: do this, do that, do the other.

Contrast "imperative" with "procedural" programming. In the latter you tell the computer what you want done: list_of_names.sort(). You don't explain the exact steps needed to sort. You tell the computer that's what you want. The computer (actually, some unsung programmer hero who came before) knows how to sort.

Let's use "hw1.rb" to create "hw2.rb", a program that emphasizes the imperative nature. The darker green lines show changes, the pink shows an addition.
# /r/hw2.rb - our second Ruby program

require 'sketchup'

UI.messagebox( "Hello" )
UI.messagebox( "World!" )

# end of /r/hw2.rb

"Hello" messagebox.  

You get "Hello" first.

"World" messagebox.  

Then "World!".

Topic: Sequential Execution

More big words for a simple concept.

The normal order of execution of statements in a program is in sequence, top to bottom.

To close this chapter we'll take a brief look at SketchTalk. That will get you modeling first from the Ruby Console and then from another Ruby you will write. Using SketchTalk requires that you know a little (actually, very little) 3D geometry.

Basic 3D Geometry

3D geometry is the topic of thick textbooks that your tutor has not read. A very few terms and concepts are all that's needed to understand the SketchUp Ruby API. That's all we'll need.

If you recall a little high school math, you remember graphs showing X on the horizontal axis, Y on the vertical axis. We'll start there.

Topic: Integers and Real Numbers

Integers are counting numbers: 0, 1, 2, ... They can also be negative: -1, -2, ...

Real numbers (horrible name!) have a decimal part: 1.0, 3.15, -333.333. Real numbers may also be called "floating point" numbers.

If you deal with very large or very small quantities you can specify the number of places to shift the decimal point this way: 14.5e9 is 14.5 billion; 2e-14 is the size, in centimeters, of a proton. (I don't know what sort of tape measure you use for this.)

Coders: In Ruby you can insert underscore characters for readability in large numbers: 1_000_000 is one million.

Coders: In Ruby an array can be written, enclosed in square brackets such as arr = [1,5,3,4] or people = ['Bob', 'Carol', 'Ted', 'Alice']. Array indexing starts at zero.

An array is a list of things. The array is the whole list. An individual element can be selected with a subscript. Subscripts in Ruby programming (and in most computer languages) are integers enclosed in square brackets. For example, assume: people = ['Bob', 'Carol', 'Ted', 'Alice']. Then people[0] is 'Bob'. people[1] is 'Carol' and so on.

Topic: Origin

In 2D geometry the "origin" is the point [0,0]. The X and Y axes cross at the origin.

In 3D geometry the origin is the point [0,0,0]. The X, Y and Z axes cross at the origin. In Sketchup, the red, green and blue axes cross at the origin.

Topic: 2D Point

A pair of numbers, which we will write as a Ruby array ([2,3]) locates a point in 2D geometry. By convention, the first number locates the point on the X axis, the second number is the Y location. [2,3] is 2 units right of the Y axis, 3 units above the X axis.

Topic: 2D Vector

A "vector" in 2D geometry is also a pair of numbers. It specifies a direction and a distance. [4,5] moves 4 units right and 5 units up. If there is no starting point specified, vectors start at the origin.

A starting point and a vector combine to form a line.

Now let's use our knowledge of 2D geometry to extend to 3D geometry. Mathematicians add the Z axis. In SketchUp the axes are colored red, green and blue and from now on we will call them "r", "g" and "b".

Topic: 3D Point

In 3D geometry a point is located on the "X", "Y" and "Z" axes, conventionally written (x, y, z). From 2D geometry, the Y axis was vertical and the X axis was horizontal. Mentally take a piece of paper, tape it to the wall and draw the X and Y axes.

Sharp pencil balanced on its eraser  

To get to 3D, take that piece of paper off your mental wall and lay it on a mental desktop so that the Y axis goes away from you as it gets higher and toward you as it gets more negative. The X axis is positive toward your right; negative towards your left. Balance a sharp wood pencil on its eraser at the X,Y origin. That is the beginning of the Z axis with higher values up, negative values down.

To locate a single point in 3D space, provide values for X, Y and Z axes.

In SketchUp, orbiting lets you fly around your model. The g and b axes can be positioned anywhere. This means that X, Y and Z no longer make much sense. Just use r, g and b, and remember the convention that the solid axes are positive, the dotted ones negative. The b axis is usually the vertical axis.

You can use a SketchUp Geom::Point3d object. For example: pt = Geom::Point3d.new( 100, 200, 300 ). You can also use an array of three numbers almost anywhere you need a point: pt = [100, 200, 300]. As the latter is much easier to type, we'll almost always use it.

Topic: Plane

In geometry (not at the airport) a plane is a flat surface extending infinitely. Think of it as a piece of paper—no folds, bends or wrinkles—with no thickness and no edges.

Topic: 3D Vector

A 3D vector is analogous to the 2D vector: it's a direction and distance. When we build our stairway (7 inch rise, 9 inch run, parallel to the red axis) we'll use [0,9,7], a vector that specifies no change in the red, 9 inches along the green axis and 7 inches along the blue (up) axis.

Topic: Vertex

A vertex is a point at which lines meet or cross. If you have more than one vertex, you have "vertices."

Topic: Orthogonal

In SketchUp the planes formed by any two axes (rg, gb or br) are orthogonal. Anything you model with lines and faces parallel to these planes is orthogonal.

A SketchUp face is a small portion of a plane. It has an inside and an outside. More exactly, there is a vector called the face's "normal" that points away from the outside. Let's Rectangle from [0,0,0] to [10,20,0]. That creates a face in the rg plane. If that face's normal is [0,0,1], the outside is facing up. Face down the normal is [0,0,-1].

Ready to put theory into practice? Let's start modeling with SketchTalk.

Modeling with SketchTalk

What is SketchTalk? It's some Ruby I've written. It's easier to demonstrate than to explain.

In our Companion Packages page download a copy of the SketchTalk package. We will be continuously working on sketch_talk.rb so don't bury it in the Plugins directory. It will be much easier if you extract it to your convenient working directory.

That package includes sketch_talk.rb and sketch_talk_classes.rb, the functions and classes, respectively, that make up SketchTalk. It also includes sketch_talk.html that you can open in your favorite browser for a summary.

Loading SketchTalk  

Begin by loading sketch_talk.rb.

Drawing a line in SketchTalk  

The initial character here is the letter that starts the word "letter", the SketchUp keyboard shortcut for the Line tool. In many fonts you can't see much difference between "l" and the digit "1". SketchTalk builds on the keyboard shortcuts, so we have to put up with this problem. Here you typed:
l [0,0,0], [-20,-20,0]
into your Ruby Console.

Almost magically, a line appears in your model between the two points.

The Ruby Console reports that it is a "Sketchup::Edge", which is much more precise. It's an "Edge" object defined in the "Sketchup" module. (Other modules could have other Edge objects. We won't get confused.)

Drawing a rectangle in SketchTalk  

The Rectangle tool is grabbed by "r". Type the following into the Ruby Console:
r [0,0,0],[-10,20,0]
You get the rectangle in your model. In the Ruby Console output you see that you've got a Rectangle object including a face, edges and other information. More, much more, on that later.

Drawing a box with SketchTalk  

SketchTalk doesn't have all the SketchUp tools. For example, there's no Orbit. (Why would your computer want to orbit your model? It wouldn't know what it was looking at. Computers are dumb.) Then, SketchUp doesn't have all the SketchTalk tools. First among them is box. Type:
box [0,0,0],[20,10,0],5
into your Ruby Console. (Maybe it's your SketchTalk console?)

box draws a Rectangle, then grabs the PushPull tool to leap into 3D existence.

You might want to try some more boxes on your own. This one shows that our boxes don't have to start in the rg plane.
box [0,0,5],[20,0,10],-10

Why -10? Try it and see. Due to no small effort, orthogonal SketchTalk boxes always PushPull toward the positive end of an axis, unless the distance is negative.

Practice a bit with these tools until you begin to think in 3D points. In Chapter 12 we'll start in the basement and then we'll use these to model that eight-command stairway. And you'll also use the donut command. Yes, that is one sweet command!


Showing off the carriage house. View of apartment contents. Donut component. Chapter 12 icon.