ydl 0.2.06
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 +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +83 -0
- data/README.org +208 -0
- data/Rakefile +6 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/examples/brief.tex +43 -0
- data/examples/cases.ydl +79 -0
- data/examples/header.rb +12 -0
- data/examples/lawyers.ydl +65 -0
- data/examples/mwe.tex +67 -0
- data/examples/persons.ydl +10 -0
- data/examples/simple.tex +23 -0
- data/examples/test_page.tex +76 -0
- data/lib/ydl/core_ext/array.rb +6 -0
- data/lib/ydl/core_ext/array_refine.rb +16 -0
- data/lib/ydl/core_ext/boolean.rb +13 -0
- data/lib/ydl/core_ext/date.rb +6 -0
- data/lib/ydl/core_ext/hash.rb +16 -0
- data/lib/ydl/core_ext/numeric.rb +6 -0
- data/lib/ydl/core_ext/string.rb +16 -0
- data/lib/ydl/core_ext.rb +7 -0
- data/lib/ydl/errors.rb +5 -0
- data/lib/ydl/node.rb +190 -0
- data/lib/ydl/top_queue.rb +40 -0
- data/lib/ydl/tree.rb +95 -0
- data/lib/ydl/version.rb +3 -0
- data/lib/ydl/ydl.rb +244 -0
- data/lib/ydl.rb +15 -0
- data/spec/array_spec.rb +14 -0
- data/spec/core_ext/array_spec.rb +23 -0
- data/spec/core_ext/boolean_spec.rb +10 -0
- data/spec/core_ext/date_spec.rb +9 -0
- data/spec/core_ext/hash_spec.rb +19 -0
- data/spec/core_ext/numeric_spec.rb +13 -0
- data/spec/core_ext/string_spec.rb +27 -0
- data/spec/example_files/err/person_err.ydl +6 -0
- data/spec/example_files/home/user/.ydl/config_template.yaml +40 -0
- data/spec/example_files/home/user/.ydl/courts/courts.ydl +28 -0
- data/spec/example_files/home/user/.ydl/lawyers.ydl +40 -0
- data/spec/example_files/home/user/.ydl/persons.ydl +9 -0
- data/spec/example_files/home/user/project/cases.ydl +59 -0
- data/spec/example_files/home/user/project/courts.ydl +7 -0
- data/spec/example_files/home/user/project/judges.ydl +27 -0
- data/spec/example_files/home/user/project/lawyers.ydl +52 -0
- data/spec/example_files/home/user/project/persons.ydl +5 -0
- data/spec/example_files/home/user/project/subproject/lawyers.ydl +85 -0
- data/spec/example_files/home/user/project/subproject/persons.ydl +55 -0
- data/spec/example_files/sys/ydl/constants.ydl +1 -0
- data/spec/example_files/sys/ydl/junk.ydl +1 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/ydl_error_spec.rb +15 -0
- data/spec/ydl_spec.rb +184 -0
- data/yaml_v_psych.rb +15 -0
- data/ydl.gemspec +40 -0
- metadata +230 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
\documentclass{article}
|
2
|
+
|
3
|
+
\usepackage{setspace}
|
4
|
+
\usepackage{array}
|
5
|
+
\usepackage{longtable}
|
6
|
+
\usepackage{yfonts}
|
7
|
+
\usepackage{calc}
|
8
|
+
\usepackage[showframe]{geometry}
|
9
|
+
|
10
|
+
\begin{document}
|
11
|
+
|
12
|
+
\setlength\extrarowheight{12pt}%
|
13
|
+
\newlength{\ldhalfwd}
|
14
|
+
\setlength{\ldhalfwd}{((\textwidth) * \real{0.95} - \columnsep)/2}%
|
15
|
+
|
16
|
+
\def\ol{%
|
17
|
+
%\begin{small}
|
18
|
+
\begin{longtable}{p{\ldhalfwd}p{\ldhalfwd}}%
|
19
|
+
\parbox[t]{\ldhalfwd}{
|
20
|
+
\textsc{Daniel E. Doherty}\\
|
21
|
+
Commerce Plaza I\\
|
22
|
+
7300 W. 110th Street, Suite 930\\
|
23
|
+
Overland Park, KS 66210\\
|
24
|
+
\textbf{Phone:} 913-338-7182\\
|
25
|
+
\textbf{Fax:} 913-338-7164\\
|
26
|
+
\textbf{Email:} \texttt{ded-law@ddoherty.net}\\
|
27
|
+
Attorney for Lisa A. Gibbons and Revive Investing LLC
|
28
|
+
}&
|
29
|
+
\parbox[t]{\ldhalfwd}{
|
30
|
+
\textsc{Charles J. Hyland}\\
|
31
|
+
Commerce Plaza I\\
|
32
|
+
7300 W. 110th Street, Suite 930\\
|
33
|
+
Overland Park, KS 66210\\
|
34
|
+
\textsc{Hyland Law Firm LLC}\\
|
35
|
+
\textbf{Phone:} 913-498-1911\\
|
36
|
+
\textbf{Fax:} 913-498-1950\\
|
37
|
+
\textbf{Email:} \texttt{charlie@hylandkc.com}\\
|
38
|
+
Attorney for Lisa A. Gibbons and Revive Investing LLC
|
39
|
+
}\\
|
40
|
+
\end{longtable}
|
41
|
+
%\end{small}
|
42
|
+
}
|
43
|
+
|
44
|
+
\thispagestyle{empty}
|
45
|
+
\setcounter{page}{-1}
|
46
|
+
{PreCaption}
|
47
|
+
\begin{center}
|
48
|
+
\hrule
|
49
|
+
\vspace{10pt}
|
50
|
+
\vfil
|
51
|
+
{\Large\gothfamily In th{e}\\
|
52
|
+
{\LARGE ForumName:}}
|
53
|
+
\vfil
|
54
|
+
\hrule
|
55
|
+
\vfil
|
56
|
+
LeftCaptionBlock
|
57
|
+
\vfil
|
58
|
+
\hrule
|
59
|
+
\vfil
|
60
|
+
\textbf{OriginatingCourt}
|
61
|
+
\vfil
|
62
|
+
\hrule
|
63
|
+
\vfil
|
64
|
+
\textsc{\bfseries DocTitle}
|
65
|
+
\vfil
|
66
|
+
\hrule
|
67
|
+
\vfil
|
68
|
+
\begin{singlespace}
|
69
|
+
\mbox{\ol}
|
70
|
+
\end{singlespace}
|
71
|
+
\vfil
|
72
|
+
\vspace{10pt}
|
73
|
+
\hrule
|
74
|
+
\end{center}
|
75
|
+
\clearpage
|
76
|
+
\end{document}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Ydl
|
2
|
+
# Extensions for Array class
|
3
|
+
module ArrayRefinements
|
4
|
+
refine Array do
|
5
|
+
# Return true of this array has other as a prefix. If self is [:a, :b,
|
6
|
+
# :c, :d], then other is a prefix if it consists of elements equal to
|
7
|
+
# the corresponding element of self through other's whole length.
|
8
|
+
def prefixed_by(other)
|
9
|
+
return false if other.length > length
|
10
|
+
|
11
|
+
residuals = zip(other).drop_while { |(a, b)| a == b }
|
12
|
+
residuals.empty? || residuals.all? { |(a, b)| !a.nil? && b.nil? }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'tsort'
|
2
|
+
|
3
|
+
# Extend Hash for use with TSort and add xref?.
|
4
|
+
class Hash
|
5
|
+
include TSort
|
6
|
+
|
7
|
+
alias tsort_each_node each_key
|
8
|
+
|
9
|
+
def tsort_each_child(node, &block)
|
10
|
+
fetch(node).each(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def xref?
|
14
|
+
values.select { |v| v.is_a?(String)}.any?(&:xref?)
|
15
|
+
end
|
16
|
+
end
|
data/lib/ydl/core_ext.rb
ADDED
data/lib/ydl/errors.rb
ADDED
data/lib/ydl/node.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
module Ydl
|
2
|
+
# A Node in a Ydl::Tree
|
3
|
+
class Node
|
4
|
+
attr_reader :path, :tree_id
|
5
|
+
attr_accessor :val, :klass, :children
|
6
|
+
|
7
|
+
def initialize(path, val, klass = nil, tree_id:)
|
8
|
+
# The path is an array of symbols representing the series of references
|
9
|
+
# taken from the root of the tree to this Node.
|
10
|
+
@path = path
|
11
|
+
# The Object id for the root Node of the tree of which this Node is a
|
12
|
+
# part.
|
13
|
+
@tree_id = tree_id
|
14
|
+
# The uninterpreted value for this Node, which when instantiated, will
|
15
|
+
# be an instance of klass. Either a Hash or a primitive type.
|
16
|
+
@val = val
|
17
|
+
|
18
|
+
# The class into which this Node should be instantiated.
|
19
|
+
@klass = klass
|
20
|
+
# child Nodes built from val; always a Hash, but keys may be numeric
|
21
|
+
# symbols, such a :'1', :'88', etc, where an sequential array-like
|
22
|
+
# structure is wanted.
|
23
|
+
@children = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return a reference to the Ydl::Tree to which this Node belongs, in case we
|
27
|
+
# instantiate more than one tree.
|
28
|
+
def our_tree
|
29
|
+
ObjectSpace._id2ref(tree_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return an Array of the
|
33
|
+
def prerequisites
|
34
|
+
result = []
|
35
|
+
if children.size.positive?
|
36
|
+
children.each_value do |child|
|
37
|
+
result += child.prerequisites
|
38
|
+
end
|
39
|
+
elsif val.instance_of?(String)
|
40
|
+
result << val if val.xref?
|
41
|
+
end
|
42
|
+
result.flatten
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return the /val/ of child at key +key+ or nil if there is none
|
46
|
+
def [](key)
|
47
|
+
return nil if children.empty?
|
48
|
+
|
49
|
+
key = key.to_s.to_sym if key.is_a?(Numeric)
|
50
|
+
children[key]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return the xref for this Node.
|
54
|
+
def xref
|
55
|
+
Tree.path_to_xref(path)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Record a dependency of this Node on a foreign Node by virtue of a
|
59
|
+
# cross-reference to the foreign Node. The argument foreign can be a
|
60
|
+
# string in the form of a Node xref or an array of xrefs.
|
61
|
+
def depends_on(foreign)
|
62
|
+
our_tree.workq.add_dependency(xref, foreign) unless foreign.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convert this Node's children to a Hash or Array.
|
66
|
+
def to_params
|
67
|
+
return {} if children.empty?
|
68
|
+
|
69
|
+
make_arr = children.keys.map(&:to_s).all? { |k| k =~ /\A[0-9]+\z/ }
|
70
|
+
result = make_arr ? [] : {}
|
71
|
+
|
72
|
+
children.each_pair do |k, child|
|
73
|
+
k = make_arr ? k.to_s.to_i : k
|
74
|
+
result[k] =
|
75
|
+
if child.children.empty? || child.instantiated?
|
76
|
+
child.val
|
77
|
+
else
|
78
|
+
child.to_params
|
79
|
+
end
|
80
|
+
rescue TypeError
|
81
|
+
warn "ydl: cannot convert #{path} with value '#{child.val}' to params"
|
82
|
+
end
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
# Recursively build the subtree of Nodes starting at this Node and set
|
87
|
+
# this node's instance variables.
|
88
|
+
#
|
89
|
+
# This Node's val is either (1) a String (not a cross-reference), (2) a
|
90
|
+
# String that is a cross reference, in which case we need to record its
|
91
|
+
# dependence on the referenced node in the Tree.workq, (3) a Hash in which
|
92
|
+
# case its elements become the children of this Node and should have their
|
93
|
+
# klass set to the class corresponding to this Node's last path key if
|
94
|
+
# it's a registered class, or (4) an Array, in which case its elements
|
95
|
+
# become the children of this Node converted into a Hash (with their
|
96
|
+
# numeric indices as keys) and its children have their klass set as with a
|
97
|
+
# Hash.
|
98
|
+
def build_subtree
|
99
|
+
child_klass = Ydl.class_for(path.last) unless path.empty?
|
100
|
+
case val
|
101
|
+
when Hash
|
102
|
+
warn "Build from Hash for class '#{child_klass}': #{val.keys.join('|')}" if child_klass
|
103
|
+
# Build child subtrees first
|
104
|
+
val.each_pair do |k, v|
|
105
|
+
# If this node names a registered class, its /children/ should be
|
106
|
+
# instantiated into that class, but this node itself should not be.
|
107
|
+
# E.g., if this node's path ends in :persons, then it is a container
|
108
|
+
# for the class Person, and its children should be instantiated into
|
109
|
+
# that class, but not the container itself. This node may also
|
110
|
+
# simply represent a parameter for a class above it, e.g., :name,
|
111
|
+
# for a Person class. We set the klass of the child to nil if it is
|
112
|
+
# either a container node or a parameter node, but we set it to the
|
113
|
+
# class if it is to be instantiated.
|
114
|
+
child = Node.new(path + [k], v, child_klass, tree_id: tree_id)
|
115
|
+
# Depth-first recursion on building the Tree.
|
116
|
+
children[k] = child.build_subtree
|
117
|
+
end
|
118
|
+
# Record the cross-reference dependencies for this Node
|
119
|
+
depends_on(prerequisites)
|
120
|
+
self.val = nil
|
121
|
+
when Array
|
122
|
+
warn "Build from Array for class '#{child_klass}'" if child_klass
|
123
|
+
val.each_with_index do |v, k|
|
124
|
+
child = Node.new(path + [k.to_s.to_sym], v, child_klass, tree_id: tree_id)
|
125
|
+
children[k.to_s.to_sym] = child.build_subtree
|
126
|
+
end
|
127
|
+
depends_on(prerequisites)
|
128
|
+
self.klass = nil
|
129
|
+
self.val = nil
|
130
|
+
when String
|
131
|
+
if val.xref?
|
132
|
+
warn "Noted cross-reference to '#{xref}'"
|
133
|
+
depends_on(val)
|
134
|
+
else
|
135
|
+
self.klass = String
|
136
|
+
end
|
137
|
+
self.children = {}
|
138
|
+
else
|
139
|
+
# E.g., Numeric, Date, DateTime
|
140
|
+
self.children = {}
|
141
|
+
self.klass = val.class
|
142
|
+
end
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return an object of class @klass if one can be initialized with the Hash
|
147
|
+
# val or the current Node converted to a params hash.
|
148
|
+
def instantiate
|
149
|
+
return nil if klass.blank?
|
150
|
+
return val if instantiated?
|
151
|
+
|
152
|
+
warn "Instantiating #{path} to #{klass} ..."
|
153
|
+
result =
|
154
|
+
if val.instance_of?(Hash)
|
155
|
+
klass.send(konstructor, **val)
|
156
|
+
else
|
157
|
+
klass.send(konstructor, **to_params)
|
158
|
+
end
|
159
|
+
warn "Instantiated #{path} to #{klass}" if result
|
160
|
+
self.val = result
|
161
|
+
end
|
162
|
+
|
163
|
+
def instantiated?
|
164
|
+
klass && val.instance_of?(klass)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Do a depth-first instantiation of this node's children, then this node.
|
168
|
+
def instantiate_subtree
|
169
|
+
children.each_value do |child|
|
170
|
+
next if child.instantiated?
|
171
|
+
|
172
|
+
child.val =
|
173
|
+
if child.children.empty?
|
174
|
+
child.instantiate
|
175
|
+
else
|
176
|
+
child.instantiate_subtree
|
177
|
+
end
|
178
|
+
end
|
179
|
+
self.val = instantiate
|
180
|
+
end
|
181
|
+
|
182
|
+
# Return a symbol for the constructor method for klass: either :new or the
|
183
|
+
# user-defined constructor from the config.
|
184
|
+
def konstructor
|
185
|
+
return nil if klass.blank?
|
186
|
+
|
187
|
+
Ydl.class_init(klass.to_s)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Ydl
|
2
|
+
# A class for keeping track of dependencies among nodes in a Ydl::Tree caused
|
3
|
+
# by the use of cross-references. This class collects those dependencies with
|
4
|
+
# #add_dependency and can return a "total ordering" consistent with the
|
5
|
+
# dependencies with its #tsort method.
|
6
|
+
class TopQueue
|
7
|
+
def initialize
|
8
|
+
@dependencies = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_dependency(dependent, depends_on)
|
12
|
+
depends_on =
|
13
|
+
case depends_on
|
14
|
+
when Array
|
15
|
+
depends_on
|
16
|
+
else
|
17
|
+
[depends_on]
|
18
|
+
end
|
19
|
+
@dependencies[dependent] ||= []
|
20
|
+
@dependencies[dependent] += depends_on
|
21
|
+
# Add an empty dependency for all the depends_on members; the TSort
|
22
|
+
# module expects this to indicate that the ref depends on nothing else.
|
23
|
+
depends_on.each do |ref|
|
24
|
+
@dependencies[ref] = [] unless @dependencies.key?(ref)
|
25
|
+
end
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def print_out
|
30
|
+
puts 'Dependencies:'
|
31
|
+
pp @dependencies.tsort
|
32
|
+
end
|
33
|
+
|
34
|
+
def topological_xrefs
|
35
|
+
@dependencies.tsort
|
36
|
+
rescue TSort::Cyclic => e
|
37
|
+
raise Ydl::CircularReference, e.to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/ydl/tree.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module Ydl
|
2
|
+
# The Tree class holds the data read from the .ydl files while any
|
3
|
+
# cross-references are being resolved and objects are being instantiated.
|
4
|
+
# After all that work is done, its nodes are merged into the main Ydl.data
|
5
|
+
# hash to be referenced by the application.
|
6
|
+
class Tree
|
7
|
+
attr_reader :tree_id, :root, :workq
|
8
|
+
|
9
|
+
# A new Tree is initialized with a Hash, which is itself a tree structure,
|
10
|
+
# but not of instantiated classes of the type we want. The nodes of the
|
11
|
+
# input hash will be basic ruby objects such as Strings, Dates, Numerics,
|
12
|
+
# and so forth, just as they are read from the ydl files by Psych. Some
|
13
|
+
# of the String objects will be in the form of cross-references to other
|
14
|
+
# parts of this tree, or of other trees that my not even exist at the time
|
15
|
+
# this one is being built.
|
16
|
+
def initialize(hsh)
|
17
|
+
@tree_id = object_id
|
18
|
+
@root = Node.new([], hsh, tree_id: @tree_id)
|
19
|
+
# A Queue of unresolved Nodes as a Hash keyed by the path to the dependent
|
20
|
+
# nodes with a value of the nodes on which that node depends.
|
21
|
+
@workq = Ydl::TopQueue.new
|
22
|
+
# Depth-first recursive build and instantiation of root node
|
23
|
+
# cross reference paths.
|
24
|
+
@root.build_subtree
|
25
|
+
instantiate
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
"Tree<#{object_id}> with top-level keys: #{@root.children.keys.join(', ')}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_hash
|
33
|
+
@root.to_params
|
34
|
+
end
|
35
|
+
|
36
|
+
# Resolution. Note: a 'xref' means a string of the form
|
37
|
+
# 'ydl:/path/to/other/object' referencing an object in another part of the
|
38
|
+
# root tree. A 'path' is an Array of Symbols such as [:path, :to, :other,
|
39
|
+
# :object], which can correspond to an xref and vice-versa. A 'node'
|
40
|
+
# means a ruby reference to the object instatiated at some path.
|
41
|
+
|
42
|
+
# Instantiate nodes in the tree in the order of any cross-references,
|
43
|
+
# topologically sorted. That is, instantiate those on which others depend
|
44
|
+
# first, and those dependent on earlier nodes last.
|
45
|
+
def instantiate
|
46
|
+
workq.topological_xrefs.each do |ref|
|
47
|
+
node = node_at_xref(ref)
|
48
|
+
if node.val.instance_of?(String) && node.val.xref?
|
49
|
+
node.val = node_at_xref(node.val).val
|
50
|
+
else
|
51
|
+
node.instantiate
|
52
|
+
end
|
53
|
+
end
|
54
|
+
@root.instantiate_subtree
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return the Ydl::Node at path in Ydl.data or nil if there is no node at
|
59
|
+
# the given path.
|
60
|
+
def node_at_path(path)
|
61
|
+
node = @root
|
62
|
+
partial_path = []
|
63
|
+
path.each do |key|
|
64
|
+
if node[key].nil?
|
65
|
+
xref = Tree.path_to_xref(path)
|
66
|
+
pxref = Tree.path_to_xref(partial_path)
|
67
|
+
klass = node.klass
|
68
|
+
msg = "can\'t resolve cross-ref '#{xref}' beyond #{klass} object '#{pxref}'"
|
69
|
+
raise Ydl::BadXRef, msg
|
70
|
+
end
|
71
|
+
partial_path << key
|
72
|
+
node = node[key]
|
73
|
+
end
|
74
|
+
node
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return the Node referenced by the given xref string
|
78
|
+
def node_at_xref(xref)
|
79
|
+
node_at_path(Tree.xref_to_path(xref))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return an Array of symbols representing a the path described by a ydl xref
|
83
|
+
# string. Return nil if str is not an xref string.
|
84
|
+
def self.xref_to_path(xref)
|
85
|
+
match = xref.to_s.clean.match(%r{\Aydl:/(?<path_str>.*)\z})
|
86
|
+
return nil unless match
|
87
|
+
|
88
|
+
match[:path_str].split('/').map(&:to_sym)
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.path_to_xref(path)
|
92
|
+
"ydl:/#{path.map(&:to_s).join('/')}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/ydl/version.rb
ADDED