module DataMetaDom::ScalaLexer

Definition for generating Scala artifacts such as case classes and everything related that depends on Scala distro only witout any other dependencies.

For command line details either check the new method's source or the README.rdoc file, the usage section.

Constants

AGGR_CLASSES

DataMeta DOM aggregated field type spec mapped to matching Scala Case class:

MAX_MAPPING_SIZE

Maximum size of a Mapping (Map), rather aribtrary choice, not backed by any big idea.

SCALA_IMPORTS

Maps DataMeta DOM datatypes to the matching Scala classes, for those that need to be imported. The Scala source generator will import these if they are used in the class.

SCALA_SUBPACKAGE

Scala Data Meta export subpackage, to distinguish between other platforms. Can not make it just “.scala” because if someone imports all the data model classes with underscore, they may pick up the “scala” subpackage too.

In which case, they will have trouble importing anything from the Scala core by “scala.*”, that violates the principle of “Least Astonishment”, they may dink around till they find out that they will have to use the root package to access the Scala core's “scala”, not the exported DataMeta “scala”.

SCALA_TYPES

A map from DataMeta DOM standard types to the lambdas that render correspondent Scala types per Scala syntax.

We used to render the primitives for the required types but the Verifiable interface made it impractical.

TEXTUAL_TYPER

Renderer for the String type.

Public Class Methods

aggrScalaType(f, scalaPackage) click to toggle source

aggregated Scala type

# File lib/dataMetaDom/scala.rb, line 125
def self.aggrScalaType(f, scalaPackage)
    rawType = self.unaggrScalaType(f.dataType, scalaPackage)
    aggr = f.aggr? ? DataMetaDom.splitNameSpace(AGGR_CLASSES[f.aggr])[1] : nil
    ScalaLexer.aggrType(aggr, f.trgType, rawType, scalaPackage)
end
aggrType(aggr, trg, rawType, scalaPackage) click to toggle source

Figures out type adjusted for aggregates and maps.

# File lib/dataMetaDom/scala.rb, line 91
def aggrType(aggr, trg, rawType, scalaPackage)
    if aggr
        k = rawType.to_sym
        subType = rawType # PRIMS_TO_WRAP.has_key?(k) ? PRIMS_TO_WRAP[k] :
        "#{aggr}[#{subType}]"
    elsif trg
        k = rawType.to_sym
        srcType = rawType
        typeRenderer = SCALA_TYPES[trg.type]
        rawTrg = typeRenderer ? typeRenderer.call(trg) : self.condenseType(self.scalaNs(trg.type), scalaPackage)
        k = rawTrg.to_sym
        trgType = rawTrg
        "Map[#{srcType}, #{trgType}]"
    else
        rawType
    end
end
condenseType(fullType, ref_namespace) click to toggle source
# File lib/dataMetaDom/scala.rb, line 111
def self.condenseType(fullType, ref_namespace)
    ns, base = DataMetaDom.splitNameSpace(fullType)
    ns = self.scalaNs(ns)
    # noinspection RubyNestedTernaryOperatorsInspection
    DataMetaDom.validNs?(ns, base) ? ( ns == ref_namespace ? base : fullType) : fullType
end
genCaseClasses(model, outRoot) click to toggle source

Generates scala sources for the model, the POJOs.

  • Parameters

    • parser - instance of Model

    • outRoot - output directory

# File lib/dataMetaDom/scala.rb, line 241
    def genCaseClasses(model, outRoot)
        firstRec = model.records.values.first
        raise ArgumentError, "No records defined in the model #{model.sources.masterPath}" unless firstRec

        scalaPackage, base, packagePath = assertNamespace(firstRec.name)
        scalaPackage = self.scalaNs(scalaPackage)
        destDir = File.join(outRoot, packagePath, SCALA_SUBPACKAGE) # keep this in sync with scalaNs
        FileUtils.mkdir_p destDir
        out = File.open(File.join(destDir, 'Model.scala'), 'wb')
        begin
            out.puts %<package #{scalaPackage}

import java.time.ZonedDateTime
import scala.math.BigDecimal
import scala.collection.immutable.Set
import scala.collection.immutable.List
import scala.collection.Seq

/**
 * This content is generated by DataMeta, do not edit manually!
 */
>

            (model.enums.values + model.records.values).each {|e|
                case
                    when e.kind_of?(DataMetaDom::Record)
                        self.genEntity model, out, e, scalaPackage
                    when e.kind_of?(DataMetaDom::Mappings)
                        raise ArgumentError, "For name #{e.name}: Mappings can not be generated to a case class"
                    when e.kind_of?(DataMetaDom::Enum)
                        self.genEnumWorded out, e
                    when e.kind_of?(DataMetaDom::BitSet)
                        raise ArgumentError, "For name #{e.name}: BitsSets can not be generated to a case class"
                    else
                        raise "Unsupported Entity: #{e.inspect}"
                end
            }
        ensure
            out.close
        end
    end
genEntity(model, out, record, scalaPackage) click to toggle source

Generates Scala source code, the Scala class for a DataMeta DOM Record

Parameters:

  • model - the source model to export from

  • out - open output file to write the result to.

  • record - instance of DataMetaDom::Record to export

  • scalaPackage - Scala package to export to

  • baseName - the name of the class to generate.

# File lib/dataMetaDom/scala.rb, line 184
    def self.genEntity(model, out, record, scalaPackage)
        baseName = record.baseName
        fields = record.fields
        out.puts <<ENTITY_CLASS_HEADER

#{record.docs.empty? ? '' : ScalaLexer.classScalaDoc(record.docs)}case class #{baseName} (
  #{fields.keys.map { |k|
            f = fields[k]
            typeDef = self.aggrScalaType(f, scalaPackage)
            "  `#{f.name}`: #{typeDef}#{model.enums.keys.member?(f.dataType.type) ? '.Value' : ''}"
        }.join(",\n  ")
  }
)
ENTITY_CLASS_HEADER
    end
genEnumWorded(out, enum) click to toggle source

Generates Scala source code for the worded enum, DataMeta DOM keyword “enum”.

# File lib/dataMetaDom/scala.rb, line 203
    def self.genEnumWorded(out, enum)
        values = enum.keys.map{|k| enum[k]} # sort by ordinals to preserve the order
        _, base, _ = assertNamespace(enum.name)
        out.puts %<

#{enum.docs.empty? ? '' : enumScalaDoc(enum.docs)}object #{base} extends Enumeration {
  type #{base} = Value
  val #{values.map{|v| "`#{v}`"}.join(', ')} = Value
}
>
    end
scalaNs(ns) click to toggle source

Distinguish JVM classes by the platform, unless it's Java

# File lib/dataMetaDom/scala.rb, line 216
def self.scalaNs(ns)
    "#{ns}.#{SCALA_SUBPACKAGE}"
end
unaggrScalaType(dt, scalaPackage) click to toggle source

Unaggregated Scala type

# File lib/dataMetaDom/scala.rb, line 119
def self.unaggrScalaType(dt, scalaPackage)
    typeRenderer = SCALA_TYPES[dt.type]
    typeRenderer ? typeRenderer.call(dt) : self.condenseType(self.scalaNs(dt.type), scalaPackage)
end

Public Instance Methods

assertNamespace(name) click to toggle source

Extracts 3 pieces of information from the given full name:

  • The namespace if any, i.e. Scala package, empty string if none

  • The base name for the type, without the namespace

  • Scala package's relative path, the dots replaced by the file separator.

Returns an array of these pieces of info in this exact order as described here.

# File lib/dataMetaDom/scala.rb, line 228
def assertNamespace(name)
    ns, base = DataMetaDom.splitNameSpace(name)
    scalaPackage = DataMetaDom.validNs?(ns, base) ? ns : ''
    packagePath = scalaPackage.empty? ? '' : scalaPackage.gsub('.', File::SEPARATOR)

    [scalaPackage, base, packagePath]
end
classScalaDoc(docs) click to toggle source

Scala Class ScalaDoc text with the Wiki reference.

# File lib/dataMetaDom/scala.rb, line 146
    def classScalaDoc(docs)
        return  <<CLASS_SCALADOC
/**
#{ScalaLexer.scalaDocs(docs)}
 */
CLASS_SCALADOC
    end
enumScalaDoc(docs) click to toggle source

Scala Enum class-level ScalaDoc text with the Wiki reference.

# File lib/dataMetaDom/scala.rb, line 157
    def enumScalaDoc(docs)
        return <<ENUM_SCALADOC
/**
#{ScalaLexer.scalaDocs(docs)}
 */
ENUM_SCALADOC
    end
getScalaType(dmDomType) click to toggle source

For the given DataMeta DOM data type and the isRequired flag, builds and returns the matching Scala data type declaration. For standard types, uses the SCALA_TYPES map

# File lib/dataMetaDom/scala.rb, line 169
def getScalaType(dmDomType)
    typeRenderer = SCALA_TYPES[dmDomType.type]
    typeRenderer ? typeRenderer.call(dmDomType) : dmDomType.type
end
scalaDocs(docs) click to toggle source

Given the property docs of Documentable, return the SCALA_DOC_TARGET if it is present, PLAIN_DOC_TARGET otherwise. Returns empty string if the argument is nil.

# File lib/dataMetaDom/scala.rb, line 134
def scalaDocs(docs)
    return '' unless docs
    case
        when docs[PLAIN_DOC_TARGET]
            docs[PLAIN_DOC_TARGET].text
        else
            ''
    end
end

Private Instance Methods

genCaseClasses(model, outRoot) click to toggle source

Generates scala sources for the model, the POJOs.

  • Parameters

    • parser - instance of Model

    • outRoot - output directory

# File lib/dataMetaDom/scala.rb, line 241
    def genCaseClasses(model, outRoot)
        firstRec = model.records.values.first
        raise ArgumentError, "No records defined in the model #{model.sources.masterPath}" unless firstRec

        scalaPackage, base, packagePath = assertNamespace(firstRec.name)
        scalaPackage = self.scalaNs(scalaPackage)
        destDir = File.join(outRoot, packagePath, SCALA_SUBPACKAGE) # keep this in sync with scalaNs
        FileUtils.mkdir_p destDir
        out = File.open(File.join(destDir, 'Model.scala'), 'wb')
        begin
            out.puts %<package #{scalaPackage}

import java.time.ZonedDateTime
import scala.math.BigDecimal
import scala.collection.immutable.Set
import scala.collection.immutable.List
import scala.collection.Seq

/**
 * This content is generated by DataMeta, do not edit manually!
 */
>

            (model.enums.values + model.records.values).each {|e|
                case
                    when e.kind_of?(DataMetaDom::Record)
                        self.genEntity model, out, e, scalaPackage
                    when e.kind_of?(DataMetaDom::Mappings)
                        raise ArgumentError, "For name #{e.name}: Mappings can not be generated to a case class"
                    when e.kind_of?(DataMetaDom::Enum)
                        self.genEnumWorded out, e
                    when e.kind_of?(DataMetaDom::BitSet)
                        raise ArgumentError, "For name #{e.name}: BitsSets can not be generated to a case class"
                    else
                        raise "Unsupported Entity: #{e.inspect}"
                end
            }
        ensure
            out.close
        end
    end