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