dataMetaDom 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a5a34ddc40e94ae5a9075a76cd8896a3b3781b76
4
+ data.tar.gz: 80d035936a0991579930f19b6bf4f8262f81c7fe
5
+ SHA512:
6
+ metadata.gz: 529782409a1e9957fba291b94318f96c7bea71f11415340039900be2a7d22d7e80761d4bfef5b5166e1b987d6dde4c5b9ea17e5e1579a9fc8194126b4508e53b
7
+ data.tar.gz: 571cb5dddc02d545731ef0ada7ea573ee033682816a13dc3122dd117229c7ba2b44a357a0e918a8c30c7661b3e71afbdcf487c904d086964c60130e33daef5c2
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --title "DataMeta DOM" -r README.md --charset UTF-8 lib/**/* - README.md
data/History.md ADDED
@@ -0,0 +1,6 @@
1
+
2
+ # `dataMetaDom` Release history:
3
+
4
+ ## `1.0.0` - `2017-01-15`
5
+ * 1 major enhancement:
6
+ * Initial release
data/PostInstall.txt ADDED
@@ -0,0 +1 @@
1
+ No special steps
data/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # dataMetaDom
2
+
3
+ The Core of the DataMeta platform, see the Features section below.
4
+
5
+ ## Description
6
+
7
+ See the [DataMeta home page](https://github.com/eBayDataMeta) and
8
+
9
+ References to this gem's:
10
+
11
+ * [Source](https://github.com/eBayDataMeta/DataMeta-gems)
12
+
13
+ ## Features
14
+
15
+ The following components are included into this gem:
16
+
17
+ * DataMetaDOM DDL parser - parses the DataMetaDOM [DDL](http://en.wikipedia.org/wiki/Data_definition_language) into
18
+ the model in memory.
19
+ * export the DataMetaDOM DDL to [POJO](http://en.wikipedia.org/wiki/Plain_Old_Java_Object) including implementors
20
+ of the `DataMetaSame` Java interface, to provide equality either by the class `identity` or by all of the
21
+ fields.
22
+ * export the DataMetaDOM DDL to MySQL DDL
23
+
24
+ ## Problems
25
+
26
+ None known.
27
+
28
+ ## Synopsis
29
+
30
+ Beside the API, there are the following runnables in this gem:
31
+
32
+ ### DataMetaDOM POJO generator.
33
+
34
+ Use this runnable to parse a DataMetaDOM source and generate Java objects
35
+ ([POJOs](http://en.wikipedia.org/wiki/Plain_Old_Java_Object)) matching the DataMeta model.
36
+
37
+ Usage:
38
+
39
+ dataMetaDomPojo.rb <DataMetaDOM source> <target directory>
40
+
41
+ Example:
42
+
43
+ dataMetaDomPojo.rb /gitrepos/projects/data/schema/showCase.dmDom ./pojos
44
+
45
+ ### DataMetaDOM MySQL DDL generator
46
+
47
+ Use this runnable to parse a DataMetaDOM DDL source and generate matching
48
+ [MySQL DDL](http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-data-definition.html) statements, including
49
+ creates, drops, creating referential integrity links and dropping those.
50
+
51
+ Usage:
52
+
53
+ dataMetaDomMySqlDdl.rb <DataMetaDOM source> <target directory>
54
+
55
+ Example:
56
+
57
+ dataMetaDomMySqlDdl.rb /gitrepos/projects/data/schema/showCase.dmDom ./sql
58
+
59
+ ### DataMetaDOM Full compare DataMetaSame generator for POJOs
60
+
61
+ Use this to generate implementors of the DataMetaSame interface from DataMetaDOM sources performing full compare.
62
+
63
+ Usage:
64
+
65
+ dataMetaDomSameFullJ.rb <DataMetaDOM source> <target directory>
66
+
67
+ ### DataMetaDOM compare by identity DataMetaSame generator for POJOs
68
+
69
+ Use this to generate implementors of the DataMetaSame interface from DataMetaDOM sources performing compare only
70
+ by the `identity` for the class, see DataMetaDom::Record for details.
71
+
72
+ Usage:
73
+
74
+ dataMetaDomSameIdJ.rb <DataMetaDOM source> <target directory>
75
+
76
+ ### Exporting DataMetaDOM source into graphical file showing entity relationships
77
+
78
+ This script generates [GraphViz](http://www.graphviz.org) source for the given DataMetaDOM module
79
+ and attempts to display the resulting jpeg file in the current OS.
80
+
81
+ Usage:
82
+
83
+ dataMetaDomGvExport.rb <DataMetaDOM source> <target base path>
84
+
85
+ The script will append the suffix `.gv` to the `target base path` for the GraphViz source and the suffix `.jpeg`
86
+ to the name of the genrated image file.
87
+
88
+ Example:
89
+
90
+ dataMetaDomGvExport.rb src/main/schema/Model.dmDom target/Model
91
+
92
+ this will generate `target/Model.gv` and `target/Model.jpeg`
93
+
94
+ This requires [GraphViz](http://www.graphviz.org) installation with the `dot` command in the path
95
+ and some kind of a graphic environment. On Windows, [Irfanview](http://www.irfanview.com) is very useful, otherwise
96
+ the script will use default Windows viewers that oftentimes are much slower.
97
+
98
+ ### Reversion all files in path
99
+
100
+ Usage:
101
+
102
+ dataMetaReVersion.rb <Path> <NS> <CSV-globs> <Ver-From> <Ver-To>
103
+
104
+ Where:
105
+
106
+ * Path - starting path to look for the files to re-version
107
+ * NS - Namespace, such as Java/Scala package
108
+ * CVS-globs - comma-separated file patterns, in regular filesystem globbing format
109
+ * Ver-From - Source version or an asterisk for any version. Example: `11.2.1`
110
+ * Ver-To - Target version. Example: `11.2.2`
111
+
112
+ Examples of arguments to this command:
113
+
114
+ * `src/main/com/acme com.acme.svc.obj.dom '*.java,*.scala' '*' 1.2.3` -- starting from the `src/main/com/acme`
115
+ directory, replace on all Scala and Java files, any DataMeta version with `1.2.3`
116
+ * `. com.acme.svc.obj.dom '*.conf,*.scala' 1.2.1 1.2.3` -- starting from the current directory,
117
+ replace on all Scala and config files, DataMeta version `1.2.1` with `1.2.3`.
118
+
119
+ Note the single quotes for the file glob patterns and the "star" specification of the source version: this is to
120
+ prevent the shell to glob before passing the result to the program.
121
+
122
+ Note that there is no relation between the path and the namespace; only Java still enforces such relation therefore
123
+ we do not want to be dependent on it.
124
+
125
+
126
+ ## Requirements
127
+
128
+ * No special requirements
129
+
130
+ ## Install
131
+
132
+ gem install dataMetaDom
133
+
134
+ ## License
135
+
136
+ [Apache v 2.0](https://github.com/eBayDataMeta/DataMeta/blob/master/LICENSE.md)
137
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ %w(yard rdoc/task rake/testtask ./lib/dataMetaDom ./lib/dataMetaDom/dataType).each{ |r| require r}
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc 'Regen RDocs'
8
+ task :default => :docs
9
+
10
+ YARD::Rake::YardocTask.new('docs') {|r|
11
+ r.stats_options = ['--list-undoc']
12
+ }
13
+
@@ -0,0 +1,97 @@
1
+ #!/bin/env ruby
2
+ %w( dataMetaDom dataMetaXtra ).each(&method(:require))
3
+ include DataMetaDom
4
+
5
+ ENTITY_FILL_COLOR='#CCEEFF'
6
+ ENUM_FILL_COLOR='#CCFFCC'
7
+ ENUM_LINE_COLOR='#00CC00'
8
+ ENTITY_LINE_COLOR='#000066'
9
+
10
+ def genGv(parser, outFileName)
11
+ out = File.open(outFileName, 'wb')
12
+ out.puts <<GV_HEADER
13
+ digraph Model {
14
+ ranksep=1.6;
15
+ node [shape=box, fontcolor="black" style="rounded,filled" fontname="Consolas" fillcolor="#AAFFCC" pad=1.5 decorate=true fontsize=15 ];
16
+ edge [arrowhead=vee] ;
17
+ GV_HEADER
18
+ parser.records.each_value.each { |rec|
19
+ ns, base = DataMetaDom::splitNameSpace(rec.name)
20
+ out.puts %{ #{base} [fillcolor = "#{ENTITY_FILL_COLOR}" color="#{ENTITY_LINE_COLOR}"]}
21
+ }
22
+ parser.enums.values.each { |e|
23
+ ns, base = DataMetaDom::splitNameSpace(e.name)
24
+ out.puts %{ #{base} [fillcolor = "#{ENUM_FILL_COLOR}" color="#{ENUM_LINE_COLOR}"]}
25
+ }
26
+
27
+ parser.records.each_value.each { |rec|
28
+ rec.refs.each { |ref|
29
+ # can not use the dotted package notation, GraphViz interprets it differently
30
+ # besides, with full names the graph becomes unreadable.
31
+ ns, fromEntityBareName = splitNameSpace ref.fromEntity.name
32
+ ns, toEntityBareName = splitNameSpace ref.toEntity.name
33
+ case ref.type
34
+ when Reference::RECORD
35
+ out.puts %{ #{fromEntityBareName} -> #{toEntityBareName} } + \
36
+ %{[ label="#{ref.fromField.name}" color="#{ENTITY_LINE_COLOR}"]}
37
+ when Reference::ENUM_REF
38
+ out.puts %{ #{fromEntityBareName} -> #{toEntityBareName} } +\
39
+ %{[ label="#{ref.fromField.name}" color="#{ENUM_LINE_COLOR}"]}
40
+ else
41
+ # skip it
42
+ end
43
+ }
44
+ }
45
+ out.puts '}'
46
+ out.close
47
+ end
48
+
49
+ def viewGv
50
+ puts `dot -o#{@imageFile} -Tjpeg #{@gvFile}`
51
+ if DataMetaXtra::Sys::WINDOWS
52
+ @imageFile.gsub!('/','\\')
53
+ irfanViewExe = %<#{ENV['PROGRAMFILES']}\\IrfanView\\i_view32.exe>
54
+ shimgvwDll = %<#{ENV['SystemRoot']}\\System32\\shimgvw.dll>
55
+ if File.file?(irfanViewExe) # if Irfanview is installed, use it because it works always faster than PhotoViewer
56
+ system(%<start "#{File.basename(@domFile)}" "#{irfanViewExe}" #{@imageFile} /title=#{File.basename(@domFile)}>)
57
+ elsif File.file?(shimgvwDll)
58
+ =begin
59
+ use the standard issue Windows PhotoViewer
60
+ if this runs too slow, run Color Calibration, or move the PhotoViewer window from one monitor to another:
61
+ if the PhotoViewer still is slow, install and use IrfanView 32 bit instead:
62
+ =end
63
+ system(%<start "#{File.basename(@domFile)}" rundll32.exe #{shimgvwDll}, ImageView_Fullscreen #{@imageFile}>)
64
+ else # use default Windows viewer for jpeg if any
65
+ system(%<start "#{File.basename(@domFile)}" #{@imageFile}>)
66
+ end
67
+ elsif DataMetaXtra::Sys::LINUX
68
+ # on Linux, ise ImageMagick, can install it with: sudo yum install php-pecl-imagick
69
+ system("display #{@imageFile} &")
70
+ # can also use "gnome-open" under GDM
71
+ else
72
+ $stderr.puts %|Don't know how to run image view on "#{RUBY_PLATFORM}"|
73
+ end
74
+
75
+ end
76
+
77
+ @domFile, @outPath = $*
78
+ raise %|DataMetaDOM source "#{@domFile}" is not a file| unless @domFile && File.file?(@domFile)
79
+ raise 'Output path is missing' unless @outPath
80
+ @outDir = File.dirname(@outPath)
81
+ raise %|Output directory "#{@outDir}" is not a directory| unless @outDir && File.directory?(@outDir)
82
+ # absolute path works best with viewer utilities and exporters too
83
+ @domBase = File.basename(@domFile, '.dmDom')
84
+ @gvFile = File.absolute_path(File.join(@outPath, @domBase + '.gv'))
85
+ @imageFile = File.absolute_path(File.join(@outPath, @domBase + '.jpeg'))
86
+
87
+
88
+ @parser = Model.new
89
+ begin
90
+ @parser.parse @domFile
91
+ genGv @parser, @gvFile
92
+ viewGv
93
+ rescue Exception => e
94
+ puts "ERROR #{e.message}#{@parser.diagn}"
95
+ puts e.backtrace.inspect
96
+ end
97
+
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # this script generates the SQL DDL for the DataMeta DOM model
3
+ # Example, from gem root:
4
+ # dataMetaMySqlDdl.rb ../../../dataMeta/showCase.dmDom ../../../../../target/sql
5
+
6
+ %w(dataMetaDom dataMetaDom/mySql dataMetaDom/help).each(&method(:require))
7
+
8
+ include DataMetaDom, DataMetaDom::MySqlLexer
9
+
10
+ @source, @target = ARGV
11
+
12
+ DataMetaDom::helpMySqlDdl __FILE__ unless @source && @target
13
+ DataMetaDom::helpMySqlDdl(__FILE__, "DataMeta DOM source #{@source} is not a file") unless File.file?(@source)
14
+ DataMetaDom::helpMySqlDdl(__FILE__, "MySQL DDL destination directory #{@target} is not a dir") unless File.directory?(@target)
15
+
16
+ @parser = Model.new
17
+ begin
18
+ @parser.parse(@source)
19
+ puts @parser.enums.values.join("\n") if $DEBUG
20
+ puts @parser.records.values.join("\n") if $DEBUG
21
+ genDdl(@parser, @target)
22
+ puts "MySQL DDL generated into #{@target}"
23
+ rescue Exception => e
24
+ $stderr.puts "ERROR #{e.message}; #{@parser.diagn}"
25
+ $stderr.puts e.backtrace.inspect
26
+ exit 1
27
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ # this script generates the SQL DDL for the DataMeta DOM core model
3
+ # Example, from gem root:
4
+ # dataMetaOracleDdl.rb ../../../dataMeta/showCase.dmDom ../../../../../target/sql
5
+
6
+ %w(dataMetaDom dataMetaDom/ora dataMetaDom/help).each(&method(:require))
7
+
8
+ include DataMetaDom, DataMetaDom::OraLexer
9
+
10
+ @source, @target = ARGV
11
+ DataMetaDom::helpOracleDdl __FILE__ unless @source && @target
12
+ DataMetaDom::helpOracleDdl(__FILE__, "DataMeta DOM source #{@source} is not a file") unless File.file?(@source)
13
+ DataMetaDom::helpOracleDdl(__FILE__, "Oracle DDL destination directory #{@target} is not a dir") unless File.directory?(@target)
14
+
15
+ @parser = Model.new
16
+ begin
17
+ @parser.parse(@source)
18
+ puts @parser.enums.values.join("\n") if $DEBUG
19
+ puts @parser.records.values.join("\n") if $DEBUG
20
+ genDdl(@parser, @target)
21
+ puts "Oracle DDL generated into #{@target}"
22
+ rescue Exception => e
23
+ $stderr.puts "ERROR #{e.message}; #{@parser.diagn}"
24
+ $stderr.puts e.backtrace.inspect
25
+ exit 1
26
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # this script generates Java POJOs and the SQL DDL for the DataMeta DOM model
3
+ # Sample:
4
+ # mkdir ../../../../../target/pojo
5
+ # dataMetaPojo.rb ../../../dataMeta/showCase.dmDom ../../../../../target/pojo
6
+
7
+ %w(dataMetaDom dataMetaDom/pojo dataMetaDom/help).each(&method(:require))
8
+
9
+ include DataMetaDom, DataMetaDom::PojoLexer
10
+
11
+ @source, @target = ARGV
12
+ DataMetaDom::helpPojoGen __FILE__ unless @source && @target
13
+ DataMetaDom::helpPojoGen(__FILE__, "DataMeta DOM source #{@source} is not a file") unless File.file?(@source)
14
+ DataMetaDom::helpPojoGen(__FILE__, "POJO destination directory #{@target} is not a dir") unless File.directory?(@target)
15
+
16
+ @parser = Model.new
17
+ begin
18
+ @parser.parse(@source, options={autoVerNs: true})
19
+ puts @parser.enums.values.join("\n") if $DEBUG
20
+ puts @parser.records.values.join("\n") if $DEBUG
21
+ genPojos(@parser, @target)
22
+ puts "POJOs written to #{@target}. Done."
23
+ rescue Exception => e
24
+ $stderr.puts "ERROR #{e.message}; #{@parser.diagn}"
25
+ $stderr.puts e.backtrace.inspect
26
+ exit 1
27
+ end
@@ -0,0 +1,66 @@
1
+ #!/bin/env ruby
2
+
3
+ # This script replaces references to DataMetaDOM version with a new version
4
+ # In the source files as well as config files.
5
+
6
+ require 'dataMetaDom'
7
+ require 'dataMetaDom/ver'
8
+ require 'dataMetaDom/help'
9
+
10
+ @path, @ns, @globs_def, @ver_from_spec, @ver_to_spec = $*
11
+
12
+ def help(errorText = nil)
13
+ DataMetaDom.help(__FILE__, 'Source reversioner', %q~<Path> <NS> <CSV-globs> <Ver-From> <Ver-To>
14
+
15
+ Where:
16
+ * Path - starting path to look for the files to re-version
17
+ * NS - Namespace, such as Java/Scala package
18
+ * CVS-globs - comma-separated file patterns, in regular filesystem globbing format
19
+ * Ver-From - Source version or an asterisk for any version. Example: 1.2.1
20
+ * Ver-To - Target version. Example: 1.2.2
21
+
22
+ Examples of arguments:
23
+ Replace on all Java and Scala files starting from the src/main/com/acme, any prior DataMeta version with 1.2.3:
24
+ src/main/com/acme com.acme.svc.schema.dom '*.java,*.scala' '*' 1.2.3
25
+
26
+ Starting from the current directory, replace on all Scala and config files, DataMeta version 1.2.1 with 1.2.3:
27
+ . com.acme.svc.schema.dom '*.conf,*.scala' 1.2.1 1.2.3
28
+
29
+ Note the single quotes for the file glob patterns and the "star" specification of the source version: this is to
30
+ prevent the shell to glob before passing the result to the program.
31
+
32
+ Note that there is no relation between the path and the namespace; only Java still enforces such relation therefore
33
+ we do not want to be dependent on it.
34
+
35
+ ~, errorText)
36
+ end
37
+
38
+ help 'Target path is missing' unless @path && !@path.empty?
39
+ help %<"#{@path}" is not a valid path!> unless File.directory?(@path)
40
+ help %<"#{@ns}" is not a valid namespace!> unless @ns.is_a?(String) && @ns =~ /^[\w_\.]+$/
41
+ help 'No file globs specified' unless @globs_def && !@globs_def.empty?
42
+ if @ver_from_spec == '*'
43
+ @ver_from = nil
44
+ else
45
+ begin
46
+ @ver_from = DataMetaDom::SemVer.new(@ver_from_spec)
47
+ rescue Exception => x
48
+ help "Source version: #{x.message}"
49
+ end
50
+ end
51
+
52
+ begin
53
+ @ver_to = DataMetaDom::SemVer.new(@ver_to_spec)
54
+ rescue Exception => x
55
+ help "Target version: #{x.message}"
56
+ end
57
+
58
+ begin
59
+ puts "Reversioning #{@globs_def} files starting from #{@path} to #{@ver_to}"
60
+ DataMetaDom::Ver.reVersion(@path, @ns, @globs_def.split(','), @ver_from, @ver_to)
61
+ puts 'Done.'
62
+ rescue Exception => x
63
+ $stderr.puts %<ERROR #{x.message}
64
+ #{x.backtrace.join("\n\t")}>
65
+ exit 1
66
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # this script generates Full Compare DataMetaSame implementors
3
+ # Sample:
4
+ # mkdir ../../../../../target/pojo
5
+ # dataMetaSameFullJ.rb ../../../dataMeta/showCase.dmDom ../../../../../target/pojo
6
+
7
+ %w(dataMetaDom dataMetaDom/pojo dataMetaDom/help).each(&method(:require))
8
+
9
+ source, target = ARGV
10
+ raise ArgumentError, 'Usage: source DataMeta DOM, target directory' unless source && target
11
+ DataMetaDom::PojoLexer.dataMetaSameRun DataMetaDom::PojoLexer::FULL_COMPARE, __FILE__, source, target
12
+
13
+ puts "All-fields DataMeta-Sames written to #{target}. Done."
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # this script generates Full Compare DataMetaSame implementors
3
+ # Sample:
4
+ # mkdir ../../../../../target/pojo
5
+ # dataMetaSameIdJ.rb ../../../schema/showCase.dmDom ../../../../../target/pojo
6
+
7
+ %w(dataMetaDom dataMetaDom/pojo dataMetaDom/help).each(&method(:require))
8
+
9
+ source, target = ARGV
10
+ raise ArgumentError, 'Usage: source DataMeta DOM, target directory' unless source && target
11
+ DataMetaDom::PojoLexer.dataMetaSameRun DataMetaDom::PojoLexer::ID_ONLY_COMPARE, __FILE__, source, target
12
+ puts "ID level DataMetaSames written to #{target}. Done."
@@ -0,0 +1,70 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ %w(fileutils set).each { |r| require r }
4
+
5
+ module DataMetaDom
6
+
7
+ =begin
8
+ Converter (ser/deser) code common to the DataMeta DOM.
9
+
10
+ For command line details either check the new method's source or the README.rdoc file, the usage section.
11
+ =end
12
+
13
+ =begin rdoc
14
+ Converter class definition, see implementations:
15
+ * INTEGRAL_CONV
16
+ * FRACT_CONV
17
+ * BOOL_CONV
18
+ * DTTM_CONV
19
+ * TEXT_CONV
20
+ =end
21
+ class Converter
22
+
23
+ =begin rdoc
24
+ Lambda converting from a data type to matching textual.
25
+ =end
26
+ attr_reader :ser
27
+
28
+ =begin rdoc
29
+ Lambda converting from a textual to matching data type.
30
+ =end
31
+ attr_reader :deser
32
+
33
+ =begin rdoc
34
+ Creates an instance with the given parameters, two lambdas, see ser and deser properties for details.
35
+ =end
36
+ def initialize(serialize, deserialize); @ser = serialize; @deser = deserialize end
37
+ end
38
+
39
+ =begin rdoc
40
+ Converter for the integral types, meaning no fraction.
41
+ =end
42
+ INTEGRAL_CONV=Converter.new(lambda { |i| i ? i.to_s : nil }, lambda { |s| s ? s.to_i : nil })
43
+
44
+ =begin rdoc
45
+ Numbers with fraction, such as real numbers, aka floating point.
46
+ =end
47
+ FRACT_CONV=Converter.new(lambda { |f| f ? f.to_s : nil }, lambda { |s| s ? s.to_f : nil })
48
+
49
+ =begin rdoc
50
+ Converter for boolean.
51
+ =end
52
+ BOOL_CONV=Converter.new(lambda { |b| b ? b.to_s : nil },
53
+ lambda { |s| s && !s.empty? ? ("TY1ty1".index(s[0]) ? true : false) : nil })
54
+ =begin rdoc
55
+ Converter for datetime.
56
+ =end
57
+ DTTM_CONV=Converter.new(lambda { |d| d ? "DateTime.parse('#{d}')" : nil }, lambda { |s| s ? DateTime.parse(s) : nil })
58
+ # DateTime.to_s does exactly what we need, no more no less
59
+
60
+ =begin rdoc
61
+ Conterter for textual types, such as string or char.
62
+ =end
63
+ TEXT_CONV=Converter.new(lambda { |src| src.inspect }, lambda { |src| eval(src) })
64
+
65
+ # All Converters hash keyed by the type, referencing an instance of the Converter class.
66
+ CONVS={INT => INTEGRAL_CONV, STRING => TEXT_CONV, CHAR => TEXT_CONV, FLOAT => FRACT_CONV, NUMERIC => FRACT_CONV,
67
+ BOOL => BOOL_CONV, DATETIME => DTTM_CONV, URL => TEXT_CONV}
68
+
69
+
70
+ end
@@ -0,0 +1,112 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ %w(fileutils set dataMetaDom/util).each { |r| require r }
4
+
5
+ module DataMetaDom
6
+
7
+ =begin rdoc
8
+ DataMeta DOM Data Type, including the base type, length if any and scale if any.
9
+
10
+ For command line details either check the new method's source or the README.rdoc file, the usage section.
11
+ =end
12
+ class DataType
13
+
14
+ =begin rdoc
15
+ Base type; either one of the standard types, see STANDARD_TYPES on the util.rb or fully named custom type
16
+ such as a Record, an Enum, a Map, a BitSet.
17
+
18
+ Use case of changing the type: multiple versions in one VM process.
19
+ =end
20
+ attr_accessor :type
21
+
22
+ =begin rdoc
23
+ For those data types that have a dimension, such as length. See DIMMED_TYPES on the util.rb.
24
+ =end
25
+ attr_reader :length
26
+
27
+ =begin rdoc
28
+ For those data types that have a scale. See SCALE_TYPES on the util.rb.
29
+ =end
30
+ attr_reader :scale
31
+
32
+ class << self
33
+ # The type must not feature a length
34
+ def mustNotDim(type)
35
+ !DIMMED_TYPES.member?(type) && !OPT_DIMMABLE.member?(type)
36
+ end
37
+
38
+ # The type must feature a length > 0
39
+ def mustDim(type)
40
+ DIMMED_TYPES.member?(type)
41
+ end
42
+
43
+ # The type may or may not feature a length
44
+ def canDim(type)
45
+ DIMMED_TYPES.member?(type) || OPT_DIMMABLE.member?(type)
46
+ end
47
+
48
+ =begin rdoc
49
+ Parses type definition from DataMeta DOM source, raising errors if anything is wrong.
50
+ Returns a new instance of the DataType.
51
+ =end
52
+ def parse(src, textual)
53
+ r = textual.scan(/([\w\.]+)(\[[\d\.]+\])?/)
54
+ raise "Invalid data type spec #{textual}" unless r
55
+ typeSpec, dimSpec = r[0]
56
+ type = typeSpec.to_sym
57
+ raise "The type #{type} can not be dimensioned" if DataType.mustNotDim(type) && dimSpec && !dimSpec.empty?
58
+ raise "The type #{type} must be dimensioned" if DataType.mustDim(type) && (!dimSpec || dimSpec.empty?)
59
+ length = nil; scale = nil
60
+ unless !dimSpec || dimSpec.empty?
61
+ raise "Invalid dimension format '#{dimSpec}'" unless dimSpec.scan(/^\[(\d+)\.?(\d+)?\]$/)
62
+ length = $1.to_i
63
+ scale = $2 ? $2.to_i : nil
64
+ end
65
+ @type = DataMetaDom.fullTypeName(src.namespace, type)
66
+ DataType.new @type, length, scale
67
+ end
68
+
69
+ end
70
+
71
+ =begin rdoc
72
+ Creates the instance with the given base type, the length and the scale
73
+ =end
74
+ def initialize(t, len=nil, scale=nil)
75
+ raise ArgumentError, "The type #{t} can not have length" if DataType.mustNotDim(t) && len
76
+
77
+ raise ArgumentError, "The type #{type} must have length > 0, but \"#{len}\" specified" \
78
+ if DataType.mustDim(t) && (!len || len < 1)
79
+
80
+ @type = t.to_sym
81
+ @length = len
82
+ @scale = scale
83
+ end
84
+
85
+ =begin rdoc
86
+ Builds a length (dimension) and scale specification for this type according to the DataMeta DOM syntax.
87
+ If the type does not have a dimension (no length, no scale), returns empty string.
88
+ =end
89
+ def length_spec; @length && @length != 0 ? "[#{@length}" + (@scale ? '.' + @scale.to_s : '') + ']' : '' end
90
+
91
+ # Textual representation of this isntance, includes the type spec with the length spec.
92
+ def to_s; "#{@type}#{length_spec}" end
93
+ end
94
+
95
+ # Reusable type - Integer of the length 1, aka Java's +byte+.
96
+ INT1 = DataType.new(INT, 1)
97
+ # Reusable type - Integer of the length 2, aka Java's +short+.
98
+ INT2 = DataType.new(INT, 2)
99
+ # Reusable type - Integer of the length 4, aka Java's +int+.
100
+ INT4 = DataType.new(INT, 4)
101
+ # Reusable type - Integer of the length 8, aka Java's +long+.
102
+ INT8 = DataType.new(INT, 8)
103
+ # Reusable type - Float (Real number) of the length 4, aka Java's +float+.
104
+ FLOAT4 = DataType.new(FLOAT, 4)
105
+ # Reusable type - Float (Real number) of the length 8, aka Java's +double+.
106
+ FLOAT8 = DataType.new(FLOAT, 8)
107
+ # Reusable type - DATETIME, in Java projected into <tt>java.time.ZonedDateTime</tt>.
108
+ DTTM_TYPE = DataType.new(DATETIME)
109
+ # Reusable type - URL, in Java projected into <tt>java.net.URL</tt>.
110
+ URL_TYPE = DataType.new(URL)
111
+
112
+ end