Skip to content

Commit ec44034

Browse files
committed
edit readme;
changes to named values (-> dictionary); unit tests complete; feature complete; initial complete;
1 parent f5bf921 commit ec44034

18 files changed

+311
-127
lines changed

README.md

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Window {
3333
```
3434

3535
Jargon is more flexible than JSON. For instance, in the example of above, there are only a couple of elements encapsulated with '"'. Also, there is no root symbol
36-
required as in JSON. A JSON document must start with `{` and close with `}`. Jargon does not require anything. As a matter of fact, one could write the following:
36+
required as in JSON. A JSON document must start with `{` and close with `}`. Jargon does not require anything. The following is a valid jargon data structure:
3737

3838
```
3939
Person {
@@ -58,8 +58,9 @@ Address {
5858
}
5959
```
6060

61-
`Person` and `Address` are separate keys with their own child nodes. Only the streets needed double quotes due to the spaces in the values. If quotes had not encapsulated
62-
the values, then street would end up as a tuple of values: ex. (123, Main, St)
61+
`Person` and `Address` are separate keys with their own child nodes. Apply double quotes to values with spaces. If quotes had not encapsulated
62+
the (street, for example) values. Otherwise, `street: 123 Main St` result is problematic.
63+
_NOTE: this behavior has not yet been determined and would most likely throw an exception._
6364

6465
If a keyed value were expected to be a list, then the following format is required:
6566

@@ -79,19 +80,30 @@ cleaner markup for a data structure than XML. Look for an implementation of Jarg
7980

8081
Jargon recognizes several formats for data:
8182

82-
integers: i:500
83-
floats: f:29.75
84-
named tuple:
85-
83+
integers: 500
84+
floats: 29.75
85+
dictionary:
8686
```
8787
size: w:500 h:500
8888
```
89+
results in: `{'w': 500, 'h': 500}`
8990

90-
results in a tuple identical to what the following Python creates:
91-
92-
```Python
93-
size = namedtuple('size', 'w h')
94-
my_size = size(500, 500)
91+
lists:
92+
```
93+
list: 100, "text information", 1/1/2000
9594
```
95+
results in: `[100, 'text information', '1/1/2000']`
9696

97-
lists: 100, "text informationn", 1/1/2000
97+
In progress (_TODO's and other stuff_):
98+
* add handling of unique node value collections, see Ex: 1
99+
* add validator (validation template)
100+
101+
Ex: 1
102+
```
103+
data: People {
104+
...
105+
}
106+
data: Addresses {
107+
...
108+
}
109+
```

__init__.py

Whitespace-only changes.

jargon_py/__init__.py

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,31 +80,57 @@ def ignore_comments(buffer, idx):
8080
return idx
8181

8282

83-
def isdigit(buffer):
83+
def iterate(tup_coll):
84+
length = None
85+
for l in tup_coll:
86+
if not length:
87+
length = len(l)
88+
continue
89+
if len(l) != length:
90+
# invalid iteration - lengths not equal
91+
raise IndexError("collection lengths not equal")
92+
93+
idx = 0
94+
while idx < length:
95+
tpl = []
96+
for l in tup_coll:
97+
tpl.append(l[idx])
98+
99+
yield tuple(tpl)
100+
101+
idx += 1
102+
103+
104+
def is_digit(buffer):
84105
digits = bytes(b'0123456789')
85106
idx = 0
86107
length = len(buffer)
87-
is_digit = True
108+
digit = True
88109
has_decimal = False
89110

90111
if buffer.startswith(b'-'):
91112
idx += 1
92113

93-
while idx < length and is_digit:
94-
is_digit = buffer[idx] in digits
95-
if not is_digit and buffer[idx] != 46: # '.'
114+
while idx < length and digit:
115+
digit = buffer[idx] in digits
116+
if not digit and buffer[idx] != 46: # '.'
96117
break
97118

98119
if not has_decimal:
99120
if buffer[idx] == 46:
100121
has_decimal = True
101-
is_digit = is_digit or True
122+
digit = digit or True
102123
elif has_decimal and buffer[idx] == 46:
103-
is_digit = is_digit and False
124+
digit = digit and False
104125

105126
idx += 1
106127

107-
return is_digit
128+
return digit
129+
130+
131+
def is_collection(candidate):
132+
import collections
133+
return not isinstance(candidate, str) and isinstance(candidate, collections.Sequence)
108134

109135

110136
def read_text(buffer, idx, escapes=True):
@@ -170,7 +196,7 @@ def decode_value(value):
170196
"""
171197
Determines if there are any special results expected from the formatting of the value:
172198
bytearray(b'w:500 h:300') expects to return a tuple with 'w' and 'h' attributes and
173-
values of 500 & 300 respective
199+
nodes of 500 & 300 respective
174200
:param value:
175201
:type value: bytearray
176202
@@ -190,7 +216,7 @@ def decode_value(value):
190216
if result and len(result):
191217
return result
192218

193-
if isdigit(value):
219+
if is_digit(value):
194220
if len(value.split(b'.')) > 1:
195221
result = float(value)
196222
elif int(value):
@@ -199,7 +225,7 @@ def decode_value(value):
199225
if result:
200226
return result
201227

202-
tags, values = ([], [])
228+
tags, nodes = ([], [])
203229
while idx < length:
204230
idx = ignore_whitespace(value, idx)
205231

@@ -215,7 +241,7 @@ def decode_value(value):
215241
temp, idx = read_text(value, idx)
216242
idx += 1
217243

218-
values.append(temp.decode())
244+
nodes.append(temp.decode())
219245
temp.clear()
220246

221247
continue
@@ -224,7 +250,7 @@ def decode_value(value):
224250
idx += 1
225251

226252
if len(temp):
227-
values.append(decode_value(temp))
253+
nodes.append(decode_value(temp))
228254
temp.clear()
229255

230256
idx += 1
@@ -233,8 +259,14 @@ def decode_value(value):
233259
temp.append(value[idx])
234260
idx += 1
235261

236-
if len(tags) and len(values):
237-
return " ".join(tags), values
262+
if len(tags) and len(nodes):
263+
node_set = {}
264+
i = 0
265+
for k, v in iterate((tags, nodes)):
266+
node_set.update({k: nodes[i]})
267+
i += 1
268+
269+
return node_set
238270

239271
if len(temp) > 0:
240272
return temp.decode()

jargon_py/jargon.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from jargon_py import *
44
from jargon_py.nodes import *
5+
from jargon_py.query import *
56

67

78
def load(file):
@@ -87,14 +88,14 @@ def build_nodes(self, raw_nodes, parent=None):
8788
buffer = self.__fso.buffer
8889
length = len(buffer)
8990

90-
key_nodes = []
91+
root = KeyNode('root', None)
9192
for n in raw_nodes:
9293
kn = KeyNode(n.name, parent)
9394

9495
if n.nodes:
95-
children = self.build_nodes(n.nodes, kn)
96+
children = self.build_nodes(n.nodes, kn).nodes
9697
for ch in children:
97-
kn.add_node(ch[1])
98+
kn.add_node(ch.node)
9899
else:
99100
# no child nodes but value instead
100101
idx = n.start
@@ -123,9 +124,10 @@ def build_nodes(self, raw_nodes, parent=None):
123124
if len(value) > 0:
124125
kn.set_value(decode_value(value))
125126

126-
key_nodes.append((kn.name, kn))
127+
root.add_node(kn)
128+
kn.parent = root
127129

128-
return key_nodes
130+
return root
129131

130132
def __scan(self, index=0, read_length=None):
131133
buffer = self.__fso.buffer
@@ -186,7 +188,7 @@ def __scan(self, index=0, read_length=None):
186188
idx += 1
187189

188190
start = idx
189-
while buffer[idx] != LINE_TERM:
191+
while idx < length and buffer[idx] != LINE_TERM:
190192
idx += 1
191193

192194
raw_node.start = start

jargon_py/nodes.py

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1+
from collections import namedtuple
12

2-
def get_nodes(collection, key):
3-
results = filter(lambda r: r[0] == key, collection)
3+
from jargon_py.query import *
44

5-
for k, n in results:
6-
yield n
7-
8-
9-
def first(iterator):
10-
item = None
11-
12-
for i in iterator:
13-
item = i
14-
break
15-
16-
return item
5+
Node = namedtuple("Node", "name node")
176

187

198
class RawNode:
@@ -49,37 +38,60 @@ def name(self):
4938
def value(self):
5039
return self.__value
5140

41+
@property
42+
def nodes(self):
43+
return self.__nodes
44+
5245
def __init__(self, key, parent):
5346
self.parent = parent
5447
self.__name = key
5548
self.__value = None
49+
self.__nodes = NodeCollection()
5650

5751
def add_node(self, node):
58-
if not self.__value:
59-
self.__value = []
60-
61-
self.__value.append((node.name, node))
52+
self.__nodes.add(node)
6253

6354
def set_value(self, value):
64-
if isinstance(value, tuple):
65-
from collections import namedtuple
66-
attribs = value[0]
67-
values = value[1]
68-
val_cls = namedtuple(self.name, attribs)
55+
self.__value = value
56+
57+
def __hash__(self):
58+
return self.__value.__hash__()
6959

70-
value = val_cls(*values)
60+
def __str__(self):
61+
return '{name}'.format(name=self.__name)
7162

72-
if not self.__value:
73-
self.__value = value
63+
def __iter__(self):
64+
return self.__nodes.__iter__()
7465

7566
def __getitem__(self, item):
76-
results = get_nodes(self.__value, item)
67+
return self.__nodes[item]
7768

78-
for v in results:
79-
yield v
8069

81-
def __hash__(self):
82-
return self.__value.__hash__()
70+
class NodeCollection:
8371

84-
def __str__(self):
85-
return '{name}'.format(name=self.__name)
72+
def __init__(self):
73+
self.__nodes = []
74+
75+
def add(self, node):
76+
"""
77+
Add a KeyNode to Collection
78+
79+
:param node: a key node object
80+
:type node: KeyNode
81+
82+
:return: void
83+
"""
84+
self.__nodes.append(Node(node.name, node))
85+
86+
def __len__(self):
87+
return len(self.__nodes)
88+
89+
def __iter__(self):
90+
for n in self.__nodes:
91+
yield n
92+
93+
def __getitem__(self, item):
94+
results = get_nodes(self.__nodes, item)
95+
96+
for r in results:
97+
yield r

jargon_py/query.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import types
2+
3+
4+
def get_nodes(collection, key):
5+
results = filter(lambda r: r.name == key, collection)
6+
7+
for k, n in results:
8+
yield n
9+
10+
11+
def first(iterator):
12+
"""
13+
Returns the first occurrence from collection iterator
14+
15+
:param iterator:
16+
17+
:return:
18+
"""
19+
item = None
20+
21+
for i in iterator:
22+
item = i
23+
break
24+
25+
return item
26+
27+
28+
def child_tags(collection):
29+
if isinstance(collection, types.GeneratorType):
30+
collection = list(collection)[0].nodes
31+
32+
return [n.name for n in collection]
33+
34+
35+
def one(iterator):
36+
"""
37+
Returns one instance found in the collection; raises exception if more than one are found
38+
39+
:param iterator:
40+
41+
:return:
42+
"""
43+
item = None
44+
45+
for i in iterator:
46+
if item is not None:
47+
raise Exception("expected only one instance but multiple exist")
48+
49+
item = i
50+
break
51+
52+
return item

jargon_py_tests/future/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)