A Little Language for Surveys: Constructing an Internal DSL in Ruby
description
Transcript of A Little Language for Surveys: Constructing an Internal DSL in Ruby
A Little Language for Surveys: A Little Language for Surveys: Constructing an Internal DSL Constructing an Internal DSL
in Rubyin Ruby
H. Conrad CunninghamH. Conrad Cunningham
Computer and Information ScienceComputer and Information ScienceUniversity of MississippiUniversity of Mississippi
22
Domain-Specific Language (DSL)Domain-Specific Language (DSL)
““programming language or executable programming language or executable specification language that offers, through specification language that offers, through appropriate notations and abstractions, appropriate notations and abstractions, expressive power focused on, and usually expressive power focused on, and usually restricted to, a particular problem domain” restricted to, a particular problem domain” – van Deursen, Klint, and Visser– van Deursen, Klint, and Visser
““little language” – J. Bentleylittle language” – J. Bentley
33
Typical DSL Characteristics Typical DSL Characteristics
Not general-purposeNot general-purpose Small (at least initially)Small (at least initially) DeclarativeDeclarative Semantically expressive of domainSemantically expressive of domain Targeted at domain specialists, Targeted at domain specialists,
not necessarily programmersnot necessarily programmers
44
External or InternalExternal or Internal
External:External: different from main different from main programming languageprogramming language– make, yacc, pic, XML-based config filesmake, yacc, pic, XML-based config files
Internal (embedded):Internal (embedded): constrained use of constrained use of the main programming languagethe main programming language– use of Lisp macros, Haskell algebraic types, use of Lisp macros, Haskell algebraic types,
metaprogramming in Ruby, etcmetaprogramming in Ruby, etc..
55
Defining Internal DSLs in Ruby Defining Internal DSLs in Ruby (1 of 2)(1 of 2)
Flexible syntax enables convenient DSL Flexible syntax enables convenient DSL statementsstatements– optional parentheses on method callsoptional parentheses on method calls– variable number of argumentsvariable number of arguments
questionquestion “Male or female?”“Male or female?”
# has optional second arg# has optional second arg
66
Defining Internal DSLs in Ruby Defining Internal DSLs in Ruby (2 of 2)(2 of 2)
Blocks (closures) provide DSL structuring Blocks (closures) provide DSL structuring and delayed executionand delayed execution– anonymous function definitionsanonymous function definitions– passed as argumentspassed as arguments
question “Male or female?” question “Male or female?” dodo
response “Male”response “Male”
response “Female” response “Female” do @fem = true enddo @fem = true end
endend
77
Implementing Internal DSLs in Ruby Implementing Internal DSLs in Ruby (1 of 2)(1 of 2)
Reflexive metaprogramming:Reflexive metaprogramming: writing programs that manipulate writing programs that manipulate themselves as data themselves as data
obj.instance_eval(str)obj.instance_eval(str) executes string executes string strstr as Ruby code in context of object as Ruby code in context of object objobj– execute DSL statements dynamicallyexecute DSL statements dynamically
mod.class_eval(str)mod.class_eval(str) executes string executes string str str as Ruby code in context of module as Ruby code in context of module modmod– declare new methods and classes dynamicallydeclare new methods and classes dynamically
88
Implementing Internal DSLs in Ruby Implementing Internal DSLs in Ruby (2 of 2)(2 of 2)
obj.method_missing(sym,*args)obj.method_missing(sym,*args) invoked when undefined method invoked when undefined method symsym called called with arguments with arguments argsargs– take remedial actiontake remedial action
obj.send(sym,*args)obj.send(sym,*args) calls method calls method symsym on object on object objobj with arguments with arguments argsargs– dynamically “send a message”dynamically “send a message”
99
Little Language for SurveysLittle Language for Surveys
Domain: Specification and presentation Domain: Specification and presentation of simple, multiple-choice surveysof simple, multiple-choice surveys
Tasks:Tasks:
1.1. Analyze domain for language designAnalyze domain for language design
2.2. Design Ruby internal DSLDesign Ruby internal DSL
3.3. Implement DSLImplement DSL
Domain AnalysisDomain Analysis
1111
Commonality/Variability AnalysisCommonality/Variability Analysis
Determine domain boundaries (scope) Determine domain boundaries (scope) Define specialized terms and concepts Define specialized terms and concepts
(terminology)(terminology) Identify unchanging features among domain Identify unchanging features among domain
members (commonalities)members (commonalities) Identify features that may change among Identify features that may change among
domain members (variabilities)domain members (variabilities)
1212
ScopeScope
Support definition of simple, multiple-Support definition of simple, multiple-choice surveyschoice surveys– specification of surveyspecification of survey– presentation of survey and collection of presentation of survey and collection of
responsesresponses Exclude tabulation of aggregate results Exclude tabulation of aggregate results
for nowfor now
1313
Terms and CommonalitiesTerms and Commonalities
1.1. Survey has a Survey has a titletitle2.2. Survey has a Survey has a sequence of questionssequence of questions3.3. Question has a Question has a sequence of responses sequence of responses 4.4. Use ofUse of conditional question conditional question depends upon depends upon
previous responsesprevious responses5.5. Response to Response to silent questionsilent question determined from determined from
previous responsesprevious responses6.6. SurveySurvey execution execution presents appropriate presents appropriate
questions to questions to respondentrespondent and collects choices of and collects choices of responsesresponses
1414
VariabilitiesVariabilities
1.1. Texts for title, questions, and responsesTexts for title, questions, and responses2.2. Number and order of questions within surveyNumber and order of questions within survey3.3. Number of responses expected for questionNumber of responses expected for question4.4. Number and order of responses in questionNumber and order of responses in question5.5. Condition under which question includedCondition under which question included6.6. Method for answering silent questionMethod for answering silent question7.7. Source of survey specificationSource of survey specification8.8. Method for displaying questions and Method for displaying questions and
collecting responses during executioncollecting responses during execution
Internal DSL DesignInternal DSL Design
1616
DSL Design StrategyDSL Design Strategy
Adopt declarative approach – structure Adopt declarative approach – structure explicit but processing implicitexplicit but processing implicit
Use terminology and commonalities to Use terminology and commonalities to suggest language statementssuggest language statements
Represent variabilities as values that Represent variabilities as values that survey programmers supplysurvey programmers supply
1717
Survey DSL Example (1 of 3)Survey DSL Example (1 of 3)
# C1 survey has title (V1)# C1 survey has title (V1)titletitle “ACMSE Survey” “ACMSE Survey”# C2 survey has seq of questions (V2)# C2 survey has seq of questions (V2)questionquestion “Are you an author?” “Are you an author?” do do # (V3)# (V3) # C3 question has seq of responses (V4)# C3 question has seq of responses (V4) responseresponse "Yes" do # execute if chosen "Yes" do # execute if chosen @author = true@author = true endend responseresponse “No” do # execute if chosen “No” do # execute if chosen @author = false @author = false endendendend
1818
Survey DSL Example (2 of 3)Survey DSL Example (2 of 3)
# C4 conditional question (V5)# C4 conditional question (V5)questionquestion "What type of paper?" do "What type of paper?" do conditioncondition { @author } # when execute? { @author } # when execute? responseresponse "Regular" do @p = :rg end "Regular" do @p = :rg end responseresponse "Student" do @p = :st end "Student" do @p = :st end responseresponse "Work-in-progress" do "Work-in-progress" do @p = :wp @p = :wp endend # V5/V6 block on response & action sets# V5/V6 block on response & action sets # state for conditions & silent choices# state for conditions & silent choices actionaction {@t = 25; @t = 15 if @p == :wp} {@t = 25; @t = 15 if @p == :wp}endend
1919
Survey DSL Example (3 of 3)Survey DSL Example (3 of 3)
# C5 silent question calculates choice (V6)# C5 silent question calculates choice (V6)resultresult "How long is presentation?“ "How long is presentation?“ dodo conditioncondition { @author } { @author } alternativealternative "25" do # when choose? "25" do # when choose? @p == :rp || @p == :sp @p == :rp || @p == :sp endend alternativealternative “15” do # when choose? “15” do # when choose? @p == :wp @p == :wp endendendend
Internal DSL ImplementationInternal DSL Implementation
2121
Two-Pass ImplementationTwo-Pass Implementation
1.1. Parse DSL and build abstract syntax Parse DSL and build abstract syntax tree (AST)tree (AST)
2.2. Execute survey by traversing ASTExecute survey by traversing AST
2222
First Pass: DSL ParsingFirst Pass: DSL Parsing
Use Use instance_evalinstance_eval to execute DSL input to execute DSL input as Ruby code (V7)as Ruby code (V7)
Let Ruby interpreter do most of parsingLet Ruby interpreter do most of parsing Add methods for each DSL statement Add methods for each DSL statement
– – titletitle, , questionquestion, , actionaction, etc., etc. Check specialized syntax and build AST as Check specialized syntax and build AST as
3-level tree (survey, question, response)3-level tree (survey, question, response) Defer conditions and actions by storing Defer conditions and actions by storing
unevaluated blocks unevaluated blocks
2323
Second Pass: DSL InterpretationSecond Pass: DSL Interpretation
Traverse AST to display questions and Traverse AST to display questions and collect responsescollect responses
Execute deferred blocks needed for Execute deferred blocks needed for conditions and actionsconditions and actions
Use Use missing_methodmissing_method and and class_evalclass_eval to create reader/writer methods for to create reader/writer methods for variables in blocksvariables in blocks
2424
ArchitectureArchitecture
First pass – use Object Scoping and First pass – use Object Scoping and Context Variable patterns for safety Context Variable patterns for safety and flexibility, Deferred Evaluation for and flexibility, Deferred Evaluation for actionsactions
Second pass – use Visitor pattern for Second pass – use Visitor pattern for flexibility (C6, V8)flexibility (C6, V8)
2525
SummarySummary
Illustrated how commonality/variability Illustrated how commonality/variability analysis can be adapted for DSL designanalysis can be adapted for DSL design
Demonstrated how Ruby facilities can Demonstrated how Ruby facilities can be used for internal DSL developmentbe used for internal DSL development
Explored how design patterns can help Explored how design patterns can help lead to safe and flexible DSL processorslead to safe and flexible DSL processors
2626
Future WorkFuture Work
More systematic techniques to explore More systematic techniques to explore domain and discover needed constructsdomain and discover needed constructs
Improved runtime error handling tied Improved runtime error handling tied to DSL inputto DSL input
Better facilities for user extensionBetter facilities for user extension Investigation and comparison of other Investigation and comparison of other
languages – Groovy, Scala, Haskelllanguages – Groovy, Scala, Haskell
2727
AcknowledgementsAcknowledgements
Members of Fall 2006 graduate class on Members of Fall 2006 graduate class on Ruby and Software DevelopmentRuby and Software Development
Suggestions on the paper by several Suggestions on the paper by several current and former studentscurrent and former students
2828
QuestionsQuestions