42
CHAPTER 2
C
ODE
GENERATION
BASICS
• Ruby supports the full range of imperative programming models from one-line
command-line invocations, to simple scripts, to functional decomposition, to full
object-oriented designs.
• Ruby can pack a lot of functionality into a small amount of code. This keeps the
code samples in the book shorter.
Ruby was designed and implemented by Yukihiro Matsumoto and released to the pub-
lic in 1995. As he put it in his introduction to the book Programming Ruby, “I wanted
a language more powerful than Perl, and more object-oriented than Python.” What he
developed was a language that is graceful, simple, consistent, and so fun and addictive
to write in that you may find yourself wanting to use it in all of your projects. 
Appendix A introduces Ruby and gives you a foundation for understanding all the
examples in this book and extrapolating that information to whatever code-generation
language you choose. You may even find that you feel comfortable enough with Ruby
to make it your implementation language.
2.6
S
UMMARY
Code generation comes in a few standard forms and you need to be familiar with each
of them and how they work in order to select the best one for your project. Although
the decision can be difficult, in general you will find that one method will always be
clearly superior to the others based on your architecture and goals.
We have also addressed some of the cultural issues around generation so that you
can better empathize with the engineering customers of your generator and address
their concerns properly. A tool that goes unused or neglected by the people it was
meant to serve provides a service to no one, so special care must be given to the suc-
cessful deployment of the tool.
This chapter provided some insights into the kinds of skills you need to write gen-
erators. In the next chapter, we examine the tools you can use to build generators. In
addition, we introduce some simple generators that you can use as templates for your
own work, as well as generators that fit vertical needs such as user interfaces, test cases,
web services, and database access.
Pdf page size dimensions - Compress reduce PDF size in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
C# Code & .NET API to Compress & Decompress PDF Document
pdf change font size in textbox; best online pdf compressor
Pdf page size dimensions - VB.NET PDF File Compress Library: Compress reduce PDF size in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
VB.NET PDF Document Compression and Decompression Control SDK
change font size pdf document; change file size of pdf document
43
C
H
A
P
T E R
3
Code generation tools
3.1 Building generators with Ruby y 43
3.2 Parsing XML with Rexml l 44
3.3 ERb: a great tool for templates s 46
3.4 Building the language parser 
toolkit 49
3.5 Summary y 60
This chapter discusses the tools used in this book for developing code generators. Like
any application, a code generator uses a set of generic tools to perform its function. In
this chapter we examine the Ruby programming language itself, as well as a utility for
reading XML, a text-template library, and a parsing toolkit for computer languages (C,
C++, Java, and SQL). All of these tools will be used in the generators presented in this
book. Regardless of whether you use these particular tools in practice, you should
familiarize yourself with them so that you can understand the example generators we
present in the book.
3.1
B
UILDING
GENERATORS
WITH
R
UBY
All of the code generators described in this book are implemented in Ruby. Ruby is a
general-purpose programming language similar to Perl or Python. One of the key
advantages to Ruby—one it shares with Perl and Python—is the ability to scale the
complexity of a program from simple scripts to elaborate object-oriented designs. The
examples in this book demonstrate Ruby’s full range—from small scripts to very large
applications. An introduction to the Ruby programming language is provided in
appendix A.
The main site for the Ruby language is www.ruby-lang.org. There you’ll find a
Ruby installation kit appropriate for your machine. Windows users should check out
www.rubycentral.com for a convenient Windows installer.
Create Thumbnail in Web Image Viewer | Online Tutorials
Height" to set your thumbnail size; Type "BackColor Barcodes from Your Documents. Multi-page Tiff Processing; RasterEdge OCR Engine; PDF Reading; Encode & Decode
300 dpi pdf file size; pdf file size
C# Imaging - C# Code 11 Generator
REImage image = new REImage(barcode.ToImage()); page.AddImage(image JPEG, PNG, GIF images and PDF, TIFF, Word barcode data // Code 11 barcode size related barcode
change font size in pdf file; best pdf compression tool
44
CHAPTER 3
C
ODE
GENERATION
TOOLS
After you have compiled and installed Ruby, you will need to install Rexml (a tool
for reading XML files) and ERb (a text-template tool). We’ll take a look at these two
utilities next.
3.2
P
ARSING
XML 
WITH
R
EXML
Although Ruby does not include an XML parser as part of its standard libraries, you
can select from among several alternatives for reading XML in Ruby—including
lib-xml, Rexml, and XMLParser. We chose Rexml for this book because of its ease of
use and portability. Rexml is written completely in Ruby, so as long as your Ruby
installation works, you can use Rexml.
To download Rexml, go to the Germane Software site (www.germane-software.-
com/software/rexml/) and download the latest release. At the time of publication, the
latest release was version 2.5.2. Installation instructions are provided on the
Germane Software site along with the source code. There you will also find an excel-
lent tutorial.
3.2.1
Using Rexml
In this section we provide some examples of using the Rexml API for reading and
writing XML files.
Reading XML text
This example shows how to read the interior text fragments within the XML node.
To start with, we need an example XML file:
<names>
<name><first>Charles</first><last>Bronson</last></name>
<name><first>Chuck</first><last>Norris</last></name>
<name><first>Stephen</first><last>Segal</last></name>
</names>
This XML defines a set of action movie actors’ names. Each name node has child first
and last nodes, which contain the first and last names of the actors as interior text.
The Ruby code shown here will read this XML and print the names:
require 'rexml/document'
doc = REXML::Document.new( File.open( "names.xml" ) )  
doc.root.each_element( "name" ) { |name_obj|          
first = name_obj.elements[ "first" ].text            
last = name_obj.elements[ "last" ].text              
print "#{first} #{last}\n"
}
q
This code creates the Rexml document object by passing the Document constructor
with an open File object.
Creates the root 
document node
q
Iterates through 
each name
w
Gets the first 
and last names
e
VB.NET Image: Compress & Decompress Document Image; RasterEdge .
Multi-page TIFF compression and decompression: lossy and decompressing: reduce Word document size according to Scanned PDF encoding and decoding: compress a
pdf markup text size; pdf files optimized
VB Imaging - VB Codabar Generator
PointF(100F, 100F)) docx.Save("C:\\Sample_Barcode.pdf"). New REImage(barcode.ToImage()) page.AddImage(image barcode data // Codabar barcode size related barcode
change font size in pdf; change font size in pdf
P
ARSING
XML 
WITH
R
EXML
45
w
This code iterates through each of the name elements within the root element. Each
name node is then passed into the block through the name_obj variable.
e
The element’s hash table is used to find the first and last nodes; then, the text
method is used to return the interior text of the node.
Reading XML attributes
Data can also be stored in the attributes of a tag. The next example shows the same data
encoded as attributes:
<names>
<name first="Charles" last="Bronson" />
<name first="Chuck" last="Norris" />
<name first="Stephen" last="Segal" />
</names>
Here, the first and last names are defined as attributes on the name node. The follow-
ing code reads the names from the attributes:
require 'rexml/document'
doc = REXML::Document.new( File.open( "names.xml" ) )
doc.root.each_element( "name" ) { |name_obj|
first = name_obj.attributes[ "first" ]                   
last = name_obj.attributes[ "last" ]                     
print "#{first} #{last}\n"
}
q
Using the attributes hash table returns the attribute with the specified name. This
returns an Attribute object, which then implicitly calls the to-string method
(to_s). This method converts the attribute value to text.
Writing updated XML
The next example builds on the previous one by adding a new attribute called
fullname to each name element. The fullname element is the concatenation of
the first and last names.
require 'rexml/document'
doc = REXML::Document.new( File.open( "names.xml" ) )
doc.root.each_element( "name" ) { |name_obj|
first = name_obj.attributes[ "first" ]
last = name_obj.attributes[ "last" ]
fullname = REXML::Attribute.new( "fullname", "#{first} #{last}" )  
name_obj.add_attribute( fullname )
}
print doc.root
Getting the first 
and last name 
attributes
q
Creating the
new attribute
q
Adding the attribute 
to the node
w
Converting the nodes back to text
e
C# Imaging - C# Codabar Generator
100F, 100F)); docx.Save(outputDirectory + "Sample_Barcode.pdf"); }. REImage(barcode. ToImage()); page.AddImage(image data // Codabar barcode size related barcode
pdf compression settings; best pdf compressor
46
CHAPTER 3
C
ODE
GENERATION
TOOLS
q
This code creates a new Attribute object by providing the key value pair of full-
name and then the concatenation of the first and last strings.
w
The add_attribute method takes a single Attribute object and adds it to the
attribute list for the element.
e
The print method implicitly calls the to_s method on the doc.root object. The
to_s method returns a text string with the full XML of the tree. 
3.3
ER
B
A
GREAT
TOOL
FOR
TEMPLATES
ERb is a text-template tool similar to JSP, ASP, PHP, or HTML::Mason. Template
tools are invaluable in code generation. Without them, the code you generate is
interspersed within the code that manages the output code, directory handling,
configuration management, and any other tasks. That mixing results in confusing and
difficult-to-maintain code. For example, when you are generating Java with Java, it is
difficult to differentiate the output Java from the generator Java.
We chose to use ERb in this book because it is small, simple, reliable, and portable.
Other template packages in Ruby require compilation; ERb does not, which means
that, like Rexml, if you can run Ruby you can use ERb.
ERb is maintained in Japan, so finding the English documentation and getting to
the download can be difficult. However, the ERb download is available on the web
site for this book, www.codegeneration.net/erb, and we have provided some simple
documentation here.
We discuss some simple alternatives to the ERb toolkit in appendix E.
3.3.1
Installing and using ERb
Once you download the install zip file, unpack it in any directory. Using the shell, run:
ruby install.rb
in the top directory. You may need root permissions to do this on a Unix system. A suc-
cessful install will tell you that files have been copied to Ruby’s site directory.
You can run ERb directly from the command line, but for our purposes this is
unnecessary. We will be invoking the ERb library from our generators and handling
the output ourselves.
This simple script reads an ERb template and executes it:
require 'erb/erb'
File.open( ARGV[0] ) { |fh|                              
erb = ERb.new( fh.read )                              
print erb.result( binding )                           
}
q
This code creates a new ERb object with the contents of the input file.
Opens the input file
q
Creates a new template
w
Runs the template
ER
B
A
GREAT
TOOL
FOR
TEMPLATES
47
w
This code runs the template and returns the output text. The binding method call
in-side the result method call is actually a call to a method called binding that
returns the variable bindings within the current context. In this case, it means that the
template will have access to the erb and fh local variables. This is how you pass
arguments to an ERb template—you create the variables within the current scope and
pass the bindings within that scope to the template.
3.3.2
ERb templates
ERb has a simple template syntax. The simplest ERb template is just text with no
replacement areas, like this:
Hello World
The result of running this template is:
Hello World
To do something more complex requires knowing the two key constructs of ERb. The
first is the <% … %>
construct, which embeds Ruby code in the template. The code is
executed, but the result is ignored for output purposes. For example:
<% name = "Jack" %>
Hello World
The output does not change: 
Hello World
Nothing new happens because the result of 
name = "Jack"
is ignored. The value of
name
is set and that code is run, but because we haven’t used the <%= … %> construct
to output the name, we would never know. Let’s remedy that:
<% name = "Jack" %>
Hello <%= name %>
This evaluates to:
Hello Jack
Now you are getting somewhere. The <%= … %> takes the result of the expression
within the block and puts it into the output stream.
Any output to standard I/O within an ERb template is output into the ERb result
stream. For example:
<% name = "Jack" %>
Hello <% print name %>
gives the same output as our earlier example, "Hello Jack". Sometimes using the
print
method can make the template easier to write and understand. You should also
notice that the <% … %> and <%= … %> constructs can span multiple lines, and
those extra lines will not appear in the output. For example:
Sets the value 
of the name 
variable
Uses the value 
of the name 
variable
Using print instead of <%= %>
48
CHAPTER 3
C
ODE
GENERATION
TOOLS
<%
name = "Jack"
%>
Hello <%= name %>
This will still result in "Hello Jack", as above. 
You should know how to use an iterator within an ERb template. It’s an important
pattern that we make extensive use of later in the book. Here is an example:
<%
names = []                                                        
names.push( { 'first' => "Jack", 'last' => "Herrington" } )       
names.push( { 'first' => "Lori", 'last' => "Herrington" } )       
names.push( { 'first' => "Megan", 'last' => "Herrington" } )      
%>
<% names.each { |name| %>                                         
Hello <%= name[ 'first' ] %> <%= name[ 'last' ] %>                
<% } %>                                                           
This code will output:
Hello Jack Herrington
Hello Lori Herrington
Hello Megan Herrington
Notice how the each method call block wraps around some ERb template code. This
makes it easy to build templates that create multiple output items.
Passing values to an ERb template
Templates don’t stand alone; you will need to pass the template values so that it can
work on them and produce an acceptable result. Passing values to an ERb template is
easy. Let’s take the 
names
example above. Here is the example host application:
require 'erb/erb'
names = []
names.push( { 'first' => "Jack", 'last' => "Herrington" } )       
names.push( { 'first' => "Lori", 'last' => "Herrington" } )       
names.push( { 'first' => "Megan", 'last' => "Herrington" } )      
File.open( ARGV[0] ) { |fh|
erb = ERb.new( fh.read )
print erb.result( binding )
}
Creates and 
populates the 
names array
Iterates through names 
and builds the output
Creates and 
populates the 
list of names
Opens the template
Creates a new ERb object with the template
Runs the template and prints the result
B
UILDING
THE
LANGUAGE
PARSER
TOOLKIT
49
The template looks like this:
<% names.each { |name| %>                                          
Hello <%= name[ 'first' ] %> <%= name[ 'last' ] %>                    
<% } %>
Here’s the resulting output:
Hello Jack Herrington
Hello Lori Herrington
Hello Megan Herrington
The template can see the names variable because of the call to binding, which
gives the ERb template handler access to all of the variables within the local scope,
including names.
3.3.3
Building ASP, JSP, etc. with ERb
One condition that can complicate using templates to build code is when your target is
another template. For example, what would happen if you needed to output the <% or
%> values to the ERb template result? The author of ERb thought of this issue and pro-
vided a solution using the <%% and %%> constructs. Here’s an example:
<edit name="<%= field %>" value="<%% myBean.get<%=  field.capitalize %>() 
%%>">
If field is equal to "first" then the output of this template will be
<edit name="first" value="<% myBean.getFirst() %>">
ready for deployment on your JSP server.
3.4
B
UILDING
THE
LANGUAGE
PARSER
TOOLKIT
Code generation often involves reading programming language code files and looking
for various language constructs, such as comments; class, function, or method
definitions; or specially formatted code fragments. For simple jobs like reading specially
formatted comments that could appear anywhere in the file, you can get by with
regular expressions. For more complex tasks—such as reading function prototypes,
matching up comments associated with particular methods or classes, or finding
function invocations—you will have to parse the language directly in order to reliably
gather the information.
For this reason a set of classes that can parse the important language features of C,
C++, Java, SQL, and PostgreSQL is provided with the code for this book. You should
be able to use these classes directly if they match your input language, or you could
use them as a starting point to parse your input language.
You can build a language parser toolkit using a standard two-phase parsing
approach. The first pass takes the input text and turns it into a set of tokens. Tokens
are a way of organizing structured text into a set of blocks, which are more easily
Iterates through 
names and builds 
the output
50
CHAPTER 3
C
ODE
GENERATION
TOOLS
parsed by downstream code. The Tokenizer classes turn the text into tokens. The
output of the Tokenizer is an object derived from an array called a TokenStream.
In the second phase, you analyze the tokens and look for specific language features.
The classes that perform this analysis derive from the LanguageScanner class. This
flow is shown in figure 3.1.
As you can see in figure 3.1, the text goes into the Tokenizer, which builds a
TokenStream. The TokenStream is taken as input by the LanguageScanner,
which analyzes the TokenStream and populates an internal store of language features.
The term language features includes elements such as function prototypes, class
definitions, comments, and table definitions. The language features that the scanner
looks for depends on the input language. For example, the CLanguageScanner,
which analyzes C code, looks for function prototypes and their associated comments.
3.4.1
Inside the Tokenizers
All of the Tokenizers build just three types of tokens: CodeTokensWhite-
spaceTokens, and CommentTokens. Figure 3.2 shows an example string of C as
it is broken out into tokens.
The segment of C in figure 3.2 is tokenized by the CTokenizer. Any text that
is not inside a comment is considered a CodeToken. For special operands (e.g., +,
-* , and ;), a new token is always created. That’s why you see b and ; as
separate tokens.
Tokenizer
TokenStream
Text
LanguageScanner
Language
Feature
Objects
Figure 3.1
The basic flow of input and output 
with the language parsing toolkit
int x = a + b; // Add a and d b\n
WhitespaceTokens
CodeTokens
CommentToken
Figure 3.2
A sample tokenization 
of a C expression
B
UILDING
THE
LANGUAGE
PARSER
TOOLKIT
51
Figure 3.3 shows the UML for the relationship between the Tokenizer,  Token-
Stream, and Tokens objects.
The Tokenizer contains an instance of the TokenStream class. Token-
Stream stores an ordered array of Tokens. TokenStream is a derived class of
Array, which adds methods that are specific to both creating and analyzing tokens.
I’ve included two Tokenizer classes with the toolkit: CTokenizer and SQL-
Tokenizer. See figure 3.4.
Both of the Tokenizer classes derive from the Tokenizer base class. SQLTo-
kenizer handles both standard SQL and PostgreSQL; CTokenizer handles C,
C++, and Java.
-text
Token
CommentToken
WhitespaceToken
CodeToken
+parse(intext)
-tokens
Tokenizer
+strip!()
+empty!()
+code_only()
+comments_only()
+find_pattern(inpattern)
+get_comments(instart)
+find(incode_value)
+find_and_remove(incode_value)
TokenStream
Figure 3.3 3 The 
Tokenizer
class and its helper classes
+parse(intext)
-tokens
Tokenizer
SQLTokenizer
CTokenizer
Figure 3.4
The family tree of the 
Tokenizer
classes
Documents you may be interested
Documents you may be interested