agreement-design-prototype 0.0.3 → 0.0.4

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.
data/src/diagram.rb CHANGED
@@ -1,67 +1,13 @@
1
1
  require 'fileutils'
2
- require_relative 'doc'
2
+ require_relative 'transform'
3
+ include Transform
3
4
 
5
+ class Diagram < Output
4
6
 
5
- class TableElement < Element
6
- def initialize file, node
7
- super(file)
8
- @node = node
9
- pput %Q("#{@node}" [label=<<table BORDER="1" CELLBORDER="0" CELLSPACING="0"><TH><TD>#{@node}</TD></TH>)
10
- @items = []
7
+ def initialize dir, name
8
+ super dir, name, ".dot"
11
9
  end
12
10
 
13
- def item i
14
- @items << i
15
- self.pput %Q(<TR><TD ALIGN="LEFT">-#{i}</TD></TR>)
16
- end
17
-
18
- def finish
19
- # self.pput " " << @items.join( ",")
20
- self.pput "</table>"
21
- self.pput ">];\n"
22
- end
23
-
24
-
25
- end
26
-
27
- class Graph < Element
28
- def initialize file
29
- super(file)
30
- self.pput "strict digraph {\n"
31
- end
32
-
33
- def finish
34
- self.pput "}\n"
35
- end
36
-
37
- end
38
-
39
- class SubGraph < Element
40
- def initialize file, model
41
- super(file)
42
- self.pput "subgraph cluster_#{model} {\n"
43
- self.pput "node [shape=plaintext margin=0];\n"
44
- self.pput "label=#{model};\n"
45
- end
46
-
47
- def finish
48
- self.pput "}\n"
49
- end
50
-
51
- end
52
-
53
- class Links < Element
54
-
55
- def link el1, el2, label: el, arrowhead: nil, arrowtail: nil
56
- ah = arrowhead ? %Q!arrowhead = "#{arrowhead}"! : ""
57
- at = arrowtail ? %Q!arrowtail = "#{arrowtail}"! : ""
58
- pput %Q!"#{el1}" -> "#{el2}" [label="#{label}" #{ah} #{at} ];\n!
59
- end
60
-
61
- end
62
-
63
- class Diagram < Doc
64
-
65
11
  def dotfile
66
12
  File.join(diagram_path, "#{self.name}.dot")
67
13
  end
@@ -75,42 +21,56 @@ class Diagram < Doc
75
21
  FileUtils.mkpath diagram_path
76
22
  FileUtils.mkpath image_path
77
23
  File.open(self.dotfile, "w") do |file|
78
- graph = Graph.new(file)
79
- for model in models
80
- subgraph = SubGraph.new(file, modelname(model))
81
- for type in model.types.values
82
- table = TableElement.new(file, typename(type))
83
- for att in type.attributes(false).values
84
- table.item att_detail(att)
85
- end
86
- table.finish
87
- end
88
- subgraph.finish
89
- end
90
- for model in models
91
- links = Links.new(file)
92
- for type in model.types.values
93
- for att in type.attributes(false).keys
94
- if type.attributes[att][:links]
95
- contains = (type.attributes[att][:type] < DataType)
96
- links.link typename(type),
97
- typename(type.attributes[att][:links]),
98
- label: %Q!#{contains ? "{contains} " : ""}#{type.attributes[att][:name]}!,
99
- arrowhead: contains ? "none": "open",
100
- arrowtail: contains ? "diamond": "none"
101
- end
102
- end
103
- if type.superclass < DataType
104
- links.link typename(type),
105
- typename(type.superclass),
24
+ # nodes
25
+ file.print "strict digraph {\n"
26
+
27
+ transform_metamodel(
28
+ {
29
+ before_model: lambda do |model:|
30
+ file.print "subgraph cluster_#{model} {\n"
31
+ file.print "node [shape=plaintext margin=0];\n"
32
+ file.print "label=#{model};\n"
33
+ end,
34
+ after_model: lambda do |model:, before:|
35
+ file.print "}\n"
36
+ end,
37
+ before_type: lambda do |type:, depth:, index:, total:|
38
+ file.print %Q("#{type.typename}" [label=<<table BORDER="1" CELLBORDER="0" CELLSPACING="0"><TH><TD>#{type.typename}</TD></TH>)
39
+ end,
40
+ after_type: lambda do |type:, depth:, before:|
41
+ file.print "</table>"
42
+ file.print ">];\n"
43
+ end,
44
+ attribute: lambda do |id:, val:, depth:, type:, index:, total:|
45
+ file.print %Q(<TR><TD ALIGN="LEFT">-#{id}</TD></TR>)
46
+ end,
47
+ },
48
+ *models
49
+ )
50
+ # links
51
+ transform_metamodel(
52
+ {
53
+ before_type: lambda do |type:, depth:, index:, total:|
54
+ if type.superclass < DataType
55
+ link(file, type.typename, type.superclass.typename,
106
56
  label: "extends",
107
57
  arrowhead: "none",
108
- arrowtail: "normal"
109
- end
110
- end
111
- links.finish
112
- end
113
- graph.finish
58
+ arrowtail: "normal")
59
+ end
60
+ end,
61
+ :attribute => lambda do |id:, val:, depth: 0, type:, index:, total:|
62
+ if val[:links] || val[:type] < DataType
63
+ contains = (val[:type] < DataType)
64
+ link(file, type.typename, val[:links] ? val[:links].typename : val[:type].typename,
65
+ label: %Q!#{contains ? "{contains} " : ""}#{val[:name]}!,
66
+ arrowhead: contains ? "none" : "open",
67
+ arrowtail: contains ? "diamond" : "none")
68
+ end
69
+ end,
70
+ },
71
+ *models
72
+ )
73
+ file.print "}\n"
114
74
  end
115
75
 
116
76
  unless system("dot -Tjpg #{self.dotfile} > #{self.jpgfile}")
@@ -136,11 +96,17 @@ class Diagram < Doc
136
96
  private
137
97
 
138
98
  def image_path
139
- File.join(self.path, "images")
99
+ File.join(self.dir, "images")
140
100
  end
141
101
 
142
102
  def diagram_path
143
- File.join(self.path, "diagrams")
103
+ File.join(self.dir, "diagrams")
104
+ end
105
+
106
+ def link file, el1, el2, label: el2, arrowhead: nil, arrowtail: nil
107
+ ah = arrowhead ? %Q!arrowhead = "#{arrowhead}"! : ""
108
+ at = arrowtail ? %Q!arrowtail = "#{arrowtail}"! : ""
109
+ file.print %Q!"#{el1}" -> "#{el2}" [label="#{label}" #{ah} #{at} ];\n!
144
110
  end
145
111
 
146
112
  end
data/src/doc.rb CHANGED
@@ -1,114 +1,61 @@
1
- class Element
2
- def initialize file
3
- @file = file
4
- end
5
-
6
- def finish
7
- self
8
- end
9
-
10
- protected
11
-
12
- def pput(string)
13
- @file.print string
14
- self
15
- end
16
-
17
- end
18
-
19
- def cond_call(depth, id, value, lam, lambdas)
20
- if lambdas[lam]
21
- return lambdas[lam].(depth, id, value)
22
- end
23
- return 0
24
- end
25
-
26
- # each lambda takes the depth, id, value
27
- # Lambdas are:
28
- # :before_type_lambda,
29
- # :after_type_lambda,
30
- # :before_array_lambda,
31
- # :after_array_lambda,
32
- # :attribute_lambda
33
- # which takes a type and returns an object (the id)
34
- # depth is the number counting from zero, incremented with array elements and nested types.
35
- # ID is a nested int of the type a for types and a.b for array types,
36
- # and is the name of the attribute for attributes
37
- # decl is the type or attribute or array
1
+ require_relative 'transform'
2
+ include Transform
38
3
 
39
- def transform_type depth, id, decl, lambdas
4
+ class Document < Output
40
5
 
41
- if decl.class <= Array
42
- cond_call(depth, id, decl, :before_array_lambda, lambdas)
43
- j = 1
44
- for aa in decl
45
- transform_type(depth , "#{id}.#{j}", aa, lambdas)
46
- j = j + 1
47
- end
48
- cond_call(depth, id, decl, :after_array_lambda, lambdas)
49
- elsif decl.class <= DataType
50
- cond_call(depth, id, decl, :before_type_lambda, lambdas)
51
- for ak in decl.attributes.keys
52
- av = decl.attributes[ak]
53
- transform_type(depth + 1, ak, av, lambdas)
54
- end
55
- cond_call(depth, id, decl, :after_type_lambda, lambdas)
56
- else
57
- cond_call(depth, id, decl, :attribute_lambda, lambdas)
6
+ def initialize dir, name
7
+ super File.join( dir, "doc"), name, "md"
58
8
  end
59
- self
60
- end
61
-
62
- class ClassNameElement < Element
63
9
 
64
- def write cat
65
- pput %Q!\# #{cat.class}: #{cat.name}\n!
66
- if (cat.respond_to?(:description))
67
- pput %Q! #{cat.description}\n!
10
+ def document *models
11
+ file do |file|
12
+ transform_datamodel(
13
+ {
14
+ :before_type => lambda do |type:, depth: 0, index:,total:|
15
+ file.print %Q!####{'#' * depth} #{type.name} #{type.attributes[:id] || ""} \n!
16
+ end,
17
+ :attribute => lambda do |id:, val:, depth: 0, type: nil, index:, total:|
18
+ file.print %Q!#{" " * depth} - #{id} #{val}\n!
19
+ end
20
+ }, *models)
68
21
  end
69
22
  end
70
23
 
71
- end
72
-
73
- class GroupElement < Element
74
-
75
- def write grpname, level: 2
76
- pput %Q! #{'#' * level} #{grpname}\n!
77
- end
78
-
79
- end
80
-
81
- class TypeDeclElement < Element
82
-
83
- def write indent, id, decl
84
- transform_type(indent, id, decl,
85
- {
86
- :before_type_lambda => lambda do |indent, id, decl|
87
- pput %Q!####{'#' * indent} #{decl.name} #{decl.attributes[:id] || id} \n!
88
- end,
89
- :attribute_lambda => lambda do |indent, id, decl|
90
- pput %Q!#{" " * indent} - #{id} #{decl}\n!
91
- end
92
- })
93
- self
94
- end
95
-
96
- end
97
-
98
- class MetaTypeElement < Element
99
-
100
- def write type
101
- pput "## #{type.typename}"
102
- if type.extends
103
- pput " extends #{type.extends}"
104
- end
105
- pput "\n #{type.description}\n\n"
106
- pput "|attribute|type|multiplicity|description|\n"
107
- pput "|---------|----|------------|-----------|\n"
108
- for a in type.attributes.values
109
- pput "|#{a[:name]}|#{a[:type]}|#{self.multiplicity(a)}|#{a[:description]}|\n"
24
+ def document_metamodel *models
25
+ file do |file|
26
+ transform_metamodel(
27
+ {
28
+ before_model: lambda do |model:|
29
+ file.print %Q!\# Data model: #{model}\n!
30
+ end,
31
+ before_group: lambda do |group|
32
+ file.print %Q!\# #{cat.class}: #{cat.name}\n!
33
+ if (cat.respond_to?(:description))
34
+ file.print %Q! #{cat.description}\n!
35
+ end
36
+ end,
37
+ before_type: lambda do |type:, depth:, index:, total:|
38
+ file.print "## #{type.typename}"
39
+ if type.extends
40
+ file.print " extends #{type.extends}"
41
+ end
42
+ file.print "\n #{type.description}\n\n"
43
+ file.print "|attribute|type|multiplicity|description|\n"
44
+ file.print "|---------|----|------------|-----------|\n"
45
+ end,
46
+ attribute: lambda do |id:, val:, type:, depth:, index:, total:|
47
+ file.print "|#{val[:name]}|#{type_and_link(val)}|#{multiplicity(val)}|#{val[:description]}|\n"
48
+ end,
49
+ before_codes: lambda do |model:|
50
+ file.print "# Codes\n"
51
+ end,
52
+ code: lambda do |model:, code:|
53
+ file.print "## #{code[:id]} #{code[:title]}\n"
54
+ file.print "#{code[:description]}\n"
55
+ file.print "#{code[:uri]}\n"
56
+ end
57
+ }, *models)
110
58
  end
111
- self
112
59
  end
113
60
 
114
61
  def multiplicity m
@@ -125,57 +72,14 @@ class MetaTypeElement < Element
125
72
  end
126
73
  return m.to_s
127
74
  end
128
- end
129
-
130
- class Doc
131
- attr_accessor :path, :name
132
75
 
133
- def initialize path, name
134
- self.path = path
135
- self.name = name
136
- end
76
+ private
137
77
 
138
- def document *models
139
- FileUtils.mkpath doc_path
140
- File.open(self.docfile, "w") do |file|
141
- for model in models
142
- dom = ClassNameElement.new(file)
143
- dom.write model
144
- for typename in model.contents.keys
145
- grp = GroupElement.new(file)
146
- grp.write typename
147
- i = 1
148
- for decl in model.contents[typename]
149
- TypeDeclElement.new(file).write(0, i, decl).finish
150
- i = i + 1
151
- end
152
- grp.finish
153
- end
154
- dom.finish
155
- end
78
+ def type_and_link(val)
79
+ if val[:links]
80
+ return "#{val[:type]} -> #{val[:links]}"
156
81
  end
157
- end
158
-
159
- def document_metamodel *models
160
- FileUtils.mkpath doc_path
161
- File.open(self.docfile, "w") do |file|
162
- for model in models
163
- dom = GroupElement.new(file)
164
- dom.write model.name, level: 1
165
- for type in model.types.values
166
- MetaTypeElement.new(file).write(type).finish
167
- end
168
- dom.finish
169
- end
170
- end
171
- end
172
-
173
- def docfile
174
- File.join(doc_path, "#{self.name}.md")
175
- end
176
-
177
- def doc_path
178
- File.join(self.path, "doc")
82
+ val[:type]
179
83
  end
180
84
 
181
85
  end
data/src/transform.rb ADDED
@@ -0,0 +1,144 @@
1
+ module Transform
2
+
3
+ class Output
4
+ public
5
+
6
+ attr_accessor :dir, :name, :ext
7
+
8
+ def initialize dir, name, ext
9
+ self.dir = dir
10
+ self.name = name
11
+ self.ext = ext
12
+ end
13
+
14
+ def filepath
15
+ File.join(self.dir, "#{name}.#{ext}")
16
+ end
17
+
18
+ def file(&block)
19
+ FileUtils.mkpath dir
20
+ File.open(filepath, "w", &block)
21
+ end
22
+ end
23
+
24
+
25
+ def before_model_lambda model: nil
26
+ return [model: model]
27
+ end
28
+
29
+ def after_model_lambda model: nil, before: nil
30
+ return [model: model, before: before]
31
+ end
32
+
33
+ def before_codes_lambda model: nil
34
+ return [model: model]
35
+ end
36
+
37
+ def code_lambda model: nil, code: nil
38
+ return [model: model, code: code]
39
+ end
40
+
41
+ def before_group_lambda name: nil, depth: 0
42
+ return [name: name, depth: depth]
43
+ end
44
+
45
+ def after_group_lambda name: nil, before: nil, depth: 0
46
+ return [name: name, before: before, depth: depth]
47
+ end
48
+
49
+ def before_type_lambda type: nil, depth: 0, index: 0, total: 1
50
+ return [type: type, depth: depth, index: index, total: total]
51
+ end
52
+
53
+ def after_type_lambda type: nil, before: nil, depth: 0
54
+ return [type: type, before: before, depth: depth]
55
+ end
56
+
57
+ def before_array_lambda name: nil, decl: nil, depth: 0, total: 1
58
+ return [name: name, decl: decl, depth: depth, total: total]
59
+ end
60
+
61
+ def after_array_lambda index: 0, decl: nil, depth: 0, before: nil
62
+ return [index: index, decl: decl, depth: depth, before: before]
63
+ end
64
+
65
+ def attribute_lambda id:, val:, depth: 0, type: nil, index:, total:
66
+ return [id: id, val: val, depth: depth, type: type, index: index, total: total]
67
+ end
68
+
69
+ # @param models - the models to transform
70
+ # @lambdas - set of function callbacks to transform
71
+
72
+ def transform_datamodel lambdas, *models
73
+ for model in models
74
+ dom = cond_call(lambdas, :before_model, *before_model_lambda(model: model))
75
+ for typename in model.contents.keys
76
+ grp = cond_call(lambdas, :before_group, *before_group_lambda(name: typename))
77
+ t = 0
78
+ # there will be more than one of each type
79
+ for type in model.contents[typename]
80
+ transform_type(lambdas, decl: type, name: typename, depth: 0, index: 0, total: 1)
81
+ t = t + 1
82
+ end
83
+ grp = cond_call(lambdas, :after_group, *after_group_lambda(name: typename, before: grp))
84
+ end
85
+ cond_call(lambdas, :after_model, *after_model_lambda(model: model, before: dom))
86
+ end
87
+ end
88
+
89
+ def transform_metamodel lambdas, *models
90
+ for model in models
91
+ dom = cond_call(lambdas, :before_model, *before_model_lambda(model: model))
92
+ for type in model.types.values
93
+ before = cond_call(lambdas, :before_type, *before_type_lambda(type: type, index:0, total:1))
94
+ i = 0
95
+ for ak in type.attributes.keys
96
+ av = type.attributes[ak]
97
+ cond_call(lambdas, :attribute, *attribute_lambda(id: ak, val: av, type: type, index: i, total: type.attributes.keys.length))
98
+ i = i + 1
99
+ end
100
+ cond_call(lambdas, :after_type, *after_type_lambda(type: type, before: before))
101
+ end
102
+ cond_call(lambdas, :after_model, *after_model_lambda(model: model, before: dom))
103
+ if model.respond_to? :codes
104
+ cond_call(lambdas, :before_codes, *before_codes_lambda(model: model))
105
+ for code in model.codes.values
106
+ cond_call(lambdas, :code, *code_lambda(model: model, code: code))
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def cond_call(lambdas, lam, *args)
113
+ if lambdas[lam]
114
+ return lambdas[lam].(*args)
115
+ end
116
+ return 0
117
+ end
118
+
119
+ def transform_type(lambdas, index:, name:, decl:, depth:, total:)
120
+
121
+ if decl.class <= Array
122
+ arrctx = cond_call(lambdas, :before_array, *before_array_lambda(name: name, decl: decl, depth: depth, total: decl.length))
123
+ j = 0
124
+ for aa in decl
125
+ transform_type(lambdas, index: j, decl: aa, name: name, depth: depth, total: decl.length)
126
+ j = j + 1
127
+ end
128
+ cond_call(lambdas, :after_array, *after_array_lambda(index: index, decl: decl, depth: depth, before: arrctx))
129
+ elsif decl.class <= DataType
130
+ before = cond_call(lambdas, :before_type, *before_type_lambda(type: decl, depth: depth, index: index, total: total))
131
+ i = 0
132
+ for ak in decl.attributes.keys
133
+ av = decl.attributes[ak]
134
+ transform_type(lambdas, name: ak, decl: av, depth: depth + 1, index: i, total: decl.attributes.keys.length)
135
+ i = i + 1
136
+ end
137
+ cond_call(lambdas, :after_type, *after_type_lambda(type: decl, depth: depth, before: before))
138
+ else
139
+ cond_call(lambdas, :attribute, *attribute_lambda(id: name, val: decl, index: index, depth: depth, total: total))
140
+ end
141
+ self
142
+ end
143
+
144
+ end