A Little Language for Surveys: Constructing an Internal DSL in Ruby

A Little Language for Surveys: Constructing an Internal DSL in Ruby

A Little Language for Surveys: Constructing an Internal DSL in Ruby H. Conrad Cunningham Department of Computer and Information Science University of Mississippi University, MS 38677 USA [email protected] ABSTRACT Fowler classifies DSLs into two styles—external and inter- Using a problem domain motivated by Bentley’s “Little Lan- nal [6]. An external DSL is a language that is different from guages” column [1], this paper explores the use of the Ruby the main programming language for an application, but that programming language’s flexible syntax, dynamic nature, is interpreted by or translated into a program in the main and reflexive metaprogramming facilities to implement an language. The little languages from the Unix platform are in A internal domain-specific language (DSL) for surveys. this category. The document preparation languages LTEX and BibTeX, which the author is using to format this pa- per, are also external DSLs. External DSLs may use ad hoc Categories and Subject Descriptors techniques, such as hand-coded delimiter-directed or recur- D.3.2 [Programming Languages]: Language Classifica- sive descent parsers [6], or may use parser-generation tools tions—Specialized application languages such as lex and yacc or ANTLR [12]. What Fowler calls an internal DSL (and Hudak calls a General Terms domain-specific embedded language [10]) transforms the main programming language itself into the DSL. This is not a Design, Languages new idea; usage of syntactic macros has been a part of the Lisp tradition for several decades. However, the features of Keywords a few contemporary languages offer new opportunities for constructing internal DSLs. Domain specific language, Ruby, reflexive metaprogramming The rise in popularity of the Ruby programming language [14] and the associated Ruby on Rails web framework [15] 1. INTRODUCTION has simulated new interest in DSLs among practitioners. In Hudak defines a domain-specific language (or DSL) as “a the Ruby environment, there is significant interest in devel- programming language tailored to a particular application oping internal DSLs [2, 8] that are made possible by the domain” [10]. DSLs are usually not general-purpose lan- extensive reflexive metaprogramming facilities of Ruby [3]. guages; they instead “trade generality for expressiveness in One interesting language of this nature is rake, a build lan- a limited domain” [11]. Thus DSLs must be precise in cap- guage implemented as a DSL in Ruby [5]. turing the semantics of their application areas [10]. They are This paper takes a problem motivated by Bentley’s “Lit- usually small, declarative languages targeted at end users or tle Languages” column [1], constructing a little language for domain specialists who are not expert programmers [10, 16]. surveys, explores the DSL capabilities of the Ruby language, DSLs, often known as little languages, have long been im- and designs an internal DSL for specifying and executing portant in the Unix operating systems community. For ex- surveys. Section 2 describes the Ruby facilities for construct- ample, in an influential 1986 column [1], Bentley describes ing internal DSLs. Section 3 analyzes the survey problem the little line-drawing language pic and its preprocessors domain and designs a simple DSL based on the analysis. Sec- scatter (a language for drawing scatter plots of two-dimen- tion 4 sketches the design and implementation of the survey sional data) and chem (a language for drawing molecular DSL processor. Sections 5 and 6 examine this work from a structures). He also describes other well-known little lan- broader perspective and conclude the paper. guages that are used to implement pic: lex for specifying lexical analyzers, yacc for specifying parsers, and make for 2. RUBY’S INTERNAL DSL SUPPORT specifying build processes. Ruby is an interpreted, dynamically typed, object-oriented application programming language with extensive metapro- gramming facilities [3, 14]. Its features are convenient for Permission to make digital or hard copies of all or part of this work for both defining and implementing DSLs. Although those tasks personal or classroom use is granted without fee provided that copies are are interrelated, it is useful to examine them separately. not made or distributed for profit or commercial advantage and that copies Ruby has two groups of features that especially support bear this notice and the full citation on the first page. To copy otherwise, to defining internal DSLs [2, 8]—its flexible syntax and its sup- republish, to post on servers or to redistribute to lists, requires prior specific port for blocks (i.e., closures). permission and/or a fee. ACM SE ’08, March 28-29, 2008, Auburn, Alabama, USA A flexible syntax is important for making DSLs read in a Copyright 2008 ACM X-XXXXX-XX-X/XX/XX ...$5.00. natural way. Of special importance is the syntax for method calls because methods are the primary means for adding provides programmers with hooks into its internal state. operators and declarators—the verbs—to an internal DSL. Ruby’s facilities include the ability to query an object to de- Ruby method calls are flexible in three key ways: the paren- termine its methods, instance variables, and class—features theses enclosing argument lists are optional, methods may that are available in mainstream languages such as Java— have a variable number of arguments, and the use of hash and also more exotic facilities such as the ability to evaluate data structures in argument lists provides a mechanism simi- strings as code, to intercept calls to undefined methods, to lar to keyword arguments. The survey DSL exploits the first define new classes and methods dynamically, and to react to two of these features. For example, the Ruby code changes in classes and methods via callback methods. Such features have long been a staple of languages such as Lisp question "Male or female?" and Smalltalk, but the recent interest in Ruby has helped renew interest in metaprogramming. calls method question with one argument, a string literal The implementation of the survey DSL uses the following giving the text for a survey question. The method question Ruby reflexive metaprogramming facilities [8, 14]: is defined with a second, optional parameter giving the ex- pected number of responses if greater than 1. If the optional obj.instance_eval(str) takes a string str and executes argument is given in a call, then it is separated from the first it as Ruby code in the context of obj. This method argument by a comma. allows internal DSL code from a string or file to be Of course, a DSL must also identify the entities to be op- executed by the Ruby interpreter. erated upon—the nouns—and their attributes—the adjec- tives. In some circumstances, the nouns may be identifiers mod.class_eval(str) takes a string str and executes it as for host language variables or classes, but, in other circum- Ruby code in the context of module mod. This enables stances, quoted string literals may need to be introduced. new methods and classes to be declared dynamically Quoted strings, with their “noisy” pairs of quotation marks, in the running program. tend to make the DSL more difficult to read and write. Ruby obj.method_missing(sym,*args) is invoked when there is provides a less “noisy” alternative, the symbol. A symbol an attempt to call an undefined method with the name is an identifier-like textual constant that is preceded by a sym and argument list args on the object obj. This colon. For example, a programmer might combine the use enables the object to take appropriate remedial action. of symbols with “keyword parameters” in a call such as obj.send(sym,*args) calls method sym on object obj with question :text => "Male or female?", :nresp => 1 argument list args. In Ruby terminology, this sends a message to the object. where the two “arguments” are collected as mappings in a hash data structure passed as an argument to the method. Now we examine how these language facilities can be used Any Ruby method call may have a block attached. A to define an internal DSL for a nontrivial domain. block (also called a Ruby Proc or a closure) is group of exe- cutable statements defined in the environment of the caller and passed unevaluated as an implicit argument to the called 3. LITTLE LANGUAGE FOR SURVEYS method. The called method may then execute the block zero The problem domain addressed here is similar to the one or more times, supplying any needed arguments for each call. for Bentley’s “little language for surveys” [1]. We first ana- The block executes with access to the environment in which lyze the domain systematically and then use the results to it was defined. As an example, consider the Ruby code design an appropriate DSL syntax and semantics. The domain is a family of applications for administering response "Female" { @female = true } simple surveys. We analyze the domain using commonal- ity/variability analysis [4] and produce four outputs. that associates a parameterless block with the one-argument method call response. When executed, the block sets in- Scope: the boundaries of the domain—what must we ad- stance variable @female to the constant true. Blocks can dress and what can we ignore. either be enclosed in a pair of braces, as above, or in a do-end construct, which is better for multi-line blocks. Terminology: definitions for the specialized terms, or con- The block feature is useful for DSL construction in at cepts, relevant to the domain. least two ways [2]. First, a block provides a structuring Commonalities: the aspects of the family of applications mechanism for DSL statements. The execution of the Ruby that do not change from one instance to another.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    6 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us