Ruby
Rosetta.rb
# Copyright (c) 2007 Art & Logic, Inc. All Rights Reserved.
# $Id: Rosetta.rb,v 1.0 2009/11/20 10:13:57 tmorgan Exp $
# Above: [sf02], [sf03]
# a note on the stuff inside the square brackets:
# Each of the codes inside brackets is a reference to the rule(s) in the
# Style Guide that's being illustrated, as follows:
# [sf##] - StyleGuide/SourceFiles
# [cas##] - StyleGuide/ClassesAndStructures
# [nr##] - StyleGuide/NamingRules
# [cg##] - StyleGuide/Commenting
# [fmt##] - StyleGuide/Formatting
# Throughout: [fmt01]; all indentation done with space characters (0x20),
# three spaces per logical tab stop.
# [nr21] C/C++ guard to prevent recursive inclusion of header files
# !!! no separate syntax is necessary to prevent this; however, to ensure
# that files are only loaded once, all includes should utilize the 'require'
# syntax in ruby (see [sf05] below). !!!
# [sf05]
require 'SomeOtherRubyFile'
# [nr25] the 'q' prefix indicates that we are controlling conditional
# compilation
# !!! Ruby is an interpreted language, so there is no need for syntax
# to control conditional compilation. !!!
# [sf07] while Ruby allows for any number of class/module definitions per
# source file, it is preferred to have a single class per file, barring
# exceptions noted in [sf07].
# [nr18] All class names should begin with a capital letter "A," followed
# immediately by another capital letter (or digit) that begins the 'real'
# name of the class.
# !!! Ruby - Modules in Ruby can be used as 'pseudo-classes,' interfaces, or for
# namespacing. When using Modules, the naming convention should be appropriate
# to the context in which the Module is used (a Module used as a Class, for
# example, should be named AModule. etc.) !!!
# [cg03] Comments should be formatted with the appropriate markup for
# automatic document extraction tools (for Ruby, this is likely to be RDoc).
# [cas01] public member functions/methods listed first
# !!! Ruby - should be listed after initialize function (constructor) for
# clarity !!!
# [nr20] global variables are prefixed with a lowercase g, followed by an
# uppercase letter beginning the variable name. Avoid using global variables.
# !!! Ruby - if a global variable is used, it is preceded with $. Thus, the
# leading g is unnecessary. !!!
$globalVariable = "Please don't use global variables."
##
# ARosetta
# Simple, but meaningless class to demonstrate Art+Logic programming
# style conventions as they are applied to the various programming languages
# we use. In several places, you're asked to imagine a block of useful code
# to avoid distracting you from the issues of formatting (etc) that are being
# demonstrated.
#
# As you've already seen above, the thing about to be shown in this file is
# called out in comments using the A+L-style markup '!!!'
class ARosetta
# [nr08] new non-class types (enumerations, data structures, etc.) are
# named with MixedCase and no special prefix
# [nr23] identifiers specifying constants for the program are always
# prefixed with a lowercase 'k'.
# !!! Ruby - no enumeration syntax, and constants are required to start
# with an uppercase letter in Ruby. In following with that, start all
# constants with an uppercase K, followed by another capital letter
# (or digit) that begins the 'real' name of the constant. !!!
KSomeConstant = 50
KSomeOtherConstant = 100
##
# Construct the Rosetta object.
def initialize
end
# !!! Ruby - no destructors in Ruby !!!
# [nr07] Member functions are named using CamelCase, with a leading upper
# case letter.
# !!! Ruby - functions must be named with a leading lower case letter. !!!
def memberFunctionWithMultipleWords
ok = true
# [fmt08] -- formatting of a for loop.
for i in (0..KSomeConstant)
for j in (0..KSomeOtherConstant)
# [fmt02] -- preprocessor directives go in column zero.
# !!! Ruby - no preprocessor directives. Logging verbosity should
# be handled by the Logger implementation (initialization assumed
# for the sake of this example) !!!
#
# !!! Ruby - method calls in Ruby do not require that parameters be
# grouped inside parentheses. For clarity and consistency purposes,
# however, parentheses should always be used to indicate method
# parameters when they are present.
OurLogger.log.debug("testing: #{i}, #{j}")
# [nr07] -- Calls to member functions of the current object are
# made through an explicit self pointer.
# !!! Ruby - there is one exception to this rule, which is that
# private methods can't be accessed through the use of a self
# pointer, due to the language architecture. Public and protected
# methods should use self where applicable, however.
ok = self.test(i, j)
unless ok
OurLogger.log.error("Fatal error test: #{i}, #{j}")
break
end
end
unless ok
break
end
end
# !!! In Ruby, return statements are not required; the result of the
# last line of code executed is always returned. However, for consistency
# and clarity, an explicit return should be used.
return ok
# [fmt02] -- labels used as the target of a goto are placed in column
# zero.
# !!! Ruby - no goto or labels. !!!
end
##
# !!! Here's how we handle very long lines (i.e., longer than 79 characters)
def longLineWrapping
# [fmt03] -- source lines should be less than 80 characters long.
# [fmt04] -- break lines at the most logical point.
# 1 2 3 4 5 6 7
#890123456789012345678901234567890123456789012345678901234567890123456789
retval = SomeStaticClass.functionWithManyArguments(longArgumentName1,
longArgumentName2, longArgumentName3, longArgumentName4)
# alternative format #1
retval = SomeStaticClass.functionWithManyArguments(longArgumentName1,
longArgumentName2,
longArgumentName3,
longArgumentName4)
# alternative format #2
retval = SomeStaticClass.functionWithManyArguments(
longArgumentName1,
longArgumentName2,
longArgumentName3,
longArgumentName4)
# [fmt05] -- prefer to break after a comma
retval = SomeStaticClass.someUsefulFunction(x.leftMargin,
x.topMargin + x.bottomMargin - 1)
# [fmt05] -- if that's not possible, break after an operator
retval = SomeStaticClass.someUsefulFunction(x.leftMargin +
anObject.horizontalPadding, x.topMargin + x.bottomMargin - 1)
return retval
end
##
# !!! Loop formatting !!!
def loops
# [fmt08] for loop
for i in (0..kSomeConstant)
# loop code here...
end
# [fmt09]
while someBooleanExpression
# useful code...
end
# [fmt09] -- while loop with an empty body makes the emptiness explicit
while self.someFuncReturningBool
# intentionally empty...
end
# [fmt10] -- do/while loop.
# Ruby does not explicitly include a do/while loop, the following syntax
# may be utilized to achieve the same effect.
begin
# loop some code here...
end while someBooleanExpression
# !!! A common method for looping in Ruby is to make use of the 'each'
# method (or other methods that iterate over a collection). An example
# of this syntax is provided, although not covered explicitly by a rule
# in the general style guide.
#
# Note that the do/end block is actually an argument to the each method on
# someCollection. In that respect, it is a necessary exception to [fmt18].
# !!!
someCollection.each do |collectionItem|
# do something with collectionItem
end
end
# [cas01] Protected member functions declared after public.
# !!! Ruby - protected is a keyword - all method/constant declarations
# following the use of this keyword are considered protected until another
# scoping keyword is used. !!!
protected
def test(firstVal, secondVal)
retval = true
# [fmt07] if/else formatting
if (firstVal < secondVal)
# [cg06] -- use '$$$' as a marker to indicate a request that the
# following block of code be reviewed before a change is considered
# complete
# $$$ before
# process(secondVal)
# $$$ after
# Shouldn't this be processing the first value in this case?
process(firstVal)
# $$$ end
elsif (secondVal > KSomeConstant)
process(secondVal)
else
# [fmt18] -- use curly braces even in cases where the language doesn't
# require it to prevent maintenance errors.
# !!! Ruby - due to syntax differences and the requirement that 'end'
# is always used to indicate the termination of a control block, this
# rule is enforced as part of the language. !!!
retval = false
end
return retval
end
# [cas01] Private member functions declared after protected.
# !!! Ruby - as with protected, 'private' is a keyword designed to alter the
# scope of all method/constant declarations that follow. !!!
private
def process(val)
# [cg05] -- use '!!!' as a marker to indicate a section of code that
# requires attention
# !!!... removing old hardcoded value
# fProcessResult = 131
# ...!!!
result = val
while (val -= 1) > 0
result *= val
end
@processResult = result
end
def decide(midiEventType)
# [fmt11] - switch/case formatting.
case midiEventType
when KNoteOn
self.noteOn(now)
if (duration > 0)
self.noteOff(now+duration)
end
when KNoteOff
self.noteOff(now)
when KPolyAfter
after = channelValue
# [fmt35] include, but comment out the break when falling through
# intentionally.
# !!! Ruby - no break is required for case statements in ruby, as
# falling through is prohibited by the language implementation.
# Therefore, this formatting rule is not applicable.
when KChannelAfter
self.afterTouch(after)
when KPitchBend
# do nothing...
# [fmt12] switch statements should always have a default case.
else
# !!! Ruby - no native support for asserts. An assert method could
# be added to the Ruby Kernel module and executed based on the
# presence of a debug command-line parameter; however, this would
# probably be better accomplished through other means.
# assert(false)
OurLogger.log.error("Unsupported event type!")
# !!! Ruby - in Ruby libraries, it is common form to use a Dictionary as a
# method argument in order to make code more 'readable' and to allow for
# an arbitrary number of arguments. It is the recommendation of this guide
# that all such Dictionaries are clearly marked with {} syntax, as opposed
# to the more ruby-conventional approach of leaving the brackets off.
# Examples below:
retval = SomeStaticClass.badDictionaryExample(a, b, c => d, e => f, g => h)
retval = SomeStaticClass.goodDictionaryExample(a, b, { c => d, e => f, g => h})
# !!!
end
end
# [cas02] member variables declared in the same order: public, protected,
# private.
# !!! Ruby - in ruby, all member variables (referred to in ruby as instance
# variables) are private by definition; there is no way to declare a public
# or protected instance variable. In the case of public variables, the ruby
# syntax for creating an attribute accessor should be used (see modValue,
# below). The attribute accessor syntax creates an instance variable with the
# given name, as well as public set/get methods for that variable. !!!
#
# [nr04], [nr19] -- class member variables always begin with a lowercase f
# followed by a single uppercase letter.
# !!! Ruby - in ruby, member variables are required to be preceded by the '@'
# symbol. In this way, the use of a lowercase f to denote that the value is a
# member variable is not necessary.
# It's also the case in ruby that member variables do not need to be declared
# before they are used. However, for the sake of clarity and consistency, all
# member variables should be defined (even if they are initialized to nil).
# !!!
attr_accessor :modValue
@filename = nil
# [fmt28] -- when declaring pointer variables, attach the '*' to the
# typename, not the variable name.
# !!! in Ruby, all variables are "pointers," so special consideration for
# pointers is not necessary. !!!
@inputFile = nil
@processResult = 0
end