ydl 0.2.06
Sign up to get free protection for your applications and to get access to all the features.
- 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