awesome-cheeba 1.0.1

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.
@@ -0,0 +1,264 @@
1
+ module Cheeba
2
+ module Reader
3
+ module Builder
4
+ #
5
+ # Abbreviations:
6
+ # adr = address
7
+ # phs = parsed hash
8
+ # hsh = hash
9
+ # lst = list
10
+ # met = meta
11
+ # cur = current
12
+ # spc = spaces
13
+ # idt = indent
14
+ # idx = index
15
+ #
16
+ # dcs = doc_start
17
+ # dct = doc_term
18
+ # hpr = hsh_pair
19
+ # hky = hsh_key
20
+ # arr = array
21
+ # com = comment
22
+ # mal = malformed
23
+ # msg = message
24
+ # bla = blank
25
+ #
26
+ class RootNodeError < StandardError; end
27
+
28
+ ##
29
+ # adds parsed_hash of line to hash
30
+ #
31
+ def self.build(hsh, phs)
32
+ add = false
33
+ upd = nil
34
+ msg = phs[:msg]
35
+ self.doc_new(hsh) if hsh.empty? && msg != "doc"
36
+ val = phs[:val]
37
+ lst = hsh[:lst]
38
+
39
+ unless [:com, :mal, :bla].include?(msg)
40
+ cur = self.cur(hsh)
41
+ key = phs[:key]
42
+ spc = phs[:spc]
43
+ idt = phs[:opt][:indent]
44
+ adr = hsh[:adr]
45
+ idx = self.index(spc, idt)
46
+ upd = self.update(adr, idx)
47
+ las = self.adr_obj(hsh, hsh[:adr])
48
+ add = true
49
+ end
50
+
51
+ case msg
52
+ when :dcs: self.doc_start(hsh)
53
+ when :dct: self.doc_term(hsh)
54
+ when :hpr: self.hsh_pair(las, key, val)
55
+ when :hky: self.hsh_key(las, adr, key)
56
+ when :bla: self.blank(lst)
57
+ when :arr
58
+ raise RootNodeError if cur.is_a?(Hash) && !cur.empty? && spc == 0
59
+ if las.is_a?(Hash) && las.empty?
60
+ self.adr_obj_to_array(hsh, hsh[:adr])
61
+ las = self.adr_obj(hsh, hsh[:adr])
62
+ end
63
+ self.arr_parse(las, adr, val, upd)
64
+ when :com: self.comment(lst, val)
65
+ when :mal: self.malformed(lst, val)
66
+ end
67
+
68
+ self.add_to_list(lst, adr) if add
69
+ end
70
+
71
+ ##
72
+ # sub-parses array message, and logic from update-method
73
+ #
74
+ def self.arr_parse(las, adr, val, upd)
75
+ case upd
76
+ when "eq": self.array_val(las, val)
77
+ when "lt": self.array_val(las, val)
78
+ when "gt": self.array_new(las, adr, val)
79
+ else; raise "error"
80
+ end
81
+ end
82
+
83
+ ##
84
+ # current hash, returns array of "doc"
85
+ #
86
+ def self.cur(hsh)
87
+ hsh[hsh.length - 2]
88
+ end
89
+
90
+ ##
91
+ # address array to string usable in eval on root node
92
+ #
93
+ def self.to_adr(adr)
94
+ m = adr.map {|x|
95
+ case
96
+ when x.is_a?(String): "['#{x}']"
97
+ when x.is_a?(Fixnum): "[#{x}]"
98
+ end
99
+ }
100
+ m.to_s
101
+ end
102
+
103
+ ##
104
+ # returns the actual object at an address in tree
105
+ #
106
+ def self.adr_obj(hsh, adr)
107
+ m = self.to_adr(adr)
108
+ eval("hsh#{m.to_s}")
109
+ end
110
+
111
+ ##
112
+ # converts an object in tree to empty array
113
+ #
114
+ def self.adr_obj_to_array(hsh, adr)
115
+ m = self.to_adr(adr)
116
+ eval("hsh#{m.to_s} = []")
117
+ end
118
+
119
+ ##
120
+ # calculates index based on spaces divided by indent unit
121
+ #
122
+ def self.index(spc, idt)
123
+ ((spc % idt) != 0) ? 0 : spc / idt
124
+ end
125
+
126
+ # if indentation less than before, jump up tree, remove extra indices
127
+ #
128
+ def self.update(adr, idx)
129
+ ret = nil
130
+ len = (adr.length - 1)
131
+ if idx < len
132
+ # remove indices after current index
133
+ adr.replace(adr[0..idx])
134
+ ret = "lt"
135
+ elsif idx == len
136
+ ret = "eq"
137
+ elsif idx > len
138
+ ret = "gt"
139
+ end
140
+ ret
141
+ end
142
+
143
+ ##
144
+ # create keypair for new doc
145
+ #
146
+ def self.doc_new(hsh)
147
+ hsh[:lst] ||= {}
148
+ hsh[:adr] ||= []
149
+ len = hsh.length - 1
150
+ hsh[len] = {}
151
+ hsh[:adr].clear
152
+ hsh[:adr] << len
153
+ end
154
+
155
+ ##
156
+ # new array in tree, provides logic for last modified object
157
+ #
158
+ def self.array_new(las, adr, val)
159
+ case
160
+ when las.is_a?(Array) && las.empty?
161
+ x = [val]
162
+ las = x
163
+ adr << las.rindex(x)
164
+ when las.is_a?(Array) && las.last.is_a?(String) && las.last.empty?
165
+ x = [val]
166
+ las[-1] = [val]
167
+ adr << las.rindex(x)
168
+ when las.is_a?(Array)
169
+ x = [val]
170
+ las << x
171
+ adr << las.rindex(x)
172
+ end
173
+ end
174
+
175
+ ##
176
+ # start document
177
+ #
178
+ def self.doc_start(hsh)
179
+ self.doc_new(hsh)
180
+ self.add_to_list(hsh[:lst], "#DOC_START")
181
+ end
182
+
183
+ ##
184
+ # document terminate
185
+ #
186
+ def self.doc_term(hsh)
187
+ self.add_to_list(hsh[:lst], "#DOC_TERM")
188
+ end
189
+
190
+ ##
191
+ # add val to array in tree
192
+ #
193
+ def self.array_val(las, val)
194
+ case
195
+ # when x is a hash, it's already addressed
196
+ when las.is_a?(Array)
197
+ las << val
198
+ else
199
+ raise las.inspect
200
+ end
201
+ end
202
+
203
+ ##
204
+ # add hashkey to tree
205
+ #
206
+ def self.hsh_key(las, adr, key)
207
+ case
208
+ when las.is_a?(Hash)
209
+ las[key] = {}
210
+ when las.is_a?(Array)
211
+ x = {key => {}}
212
+ las << x
213
+ adr << las.rindex(x)
214
+ end
215
+ adr << key
216
+ end
217
+
218
+ ##
219
+ # add hashpair to tree
220
+ #
221
+ def self.hsh_pair(las, key, val)
222
+ case
223
+ when las.is_a?(Array)
224
+ x = {key => val}
225
+ las << x
226
+ when las.is_a?(Hash)
227
+ las[key] = val
228
+ end
229
+ end
230
+
231
+ ##
232
+ # list stores hsh addresses of lines, comments, etc.
233
+ #
234
+ def self.add_to_list(lst, adr)
235
+ case adr.class.to_s
236
+ when "String": x = adr
237
+ when "Array": x = adr.join(",")
238
+ end
239
+ lst[lst.length + 1] = x
240
+ end
241
+
242
+ ##
243
+ # add blank to list
244
+ #
245
+ def self.blank(lst)
246
+ self.add_to_list(lst, "#BLANK")
247
+ end
248
+
249
+ ##
250
+ # add comment to list
251
+ #
252
+ def self.comment(lst, val)
253
+ lst[lst.length + 1] = "#COMMENT: #{val}"
254
+ end
255
+
256
+ ##
257
+ # add malformed to list
258
+ #
259
+ def self.malformed(lst, val)
260
+ lst[lst.length + 1] = "#MALFORMED: #{val}"
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,126 @@
1
+ module Cheeba
2
+ module Reader
3
+ module Format
4
+ ##
5
+ # format datatypes in the parsed hash
6
+ #
7
+ def self.format(phs)
8
+ self.adjust_options(phs)
9
+ self.stripper(phs)
10
+ self.key_to_int(phs)
11
+ self.val_to_int(phs)
12
+ self.key_to_sym(phs)
13
+ self.val_to_sym(phs)
14
+ self.key_to_true(phs)
15
+ self.val_to_true(phs)
16
+ phs
17
+ end
18
+
19
+ ##
20
+ # strips keys and values
21
+ #
22
+ def self.stripper(phs)
23
+ psp = phs[:opt][:strip]
24
+ psk = phs[:opt][:strip_keys]
25
+ psv = phs[:opt][:strip_vals]
26
+ phs[:key] = phs[:key].to_s.strip if psp or psk
27
+ phs[:val] = phs[:val].to_s.strip if psp or psv
28
+ end
29
+
30
+ ##
31
+ # adjusts options
32
+ #
33
+ def self.adjust_options(phs)
34
+ if phs[:opt][:auto_sym]
35
+ phs[:opt][:auto_sym_keys] = true
36
+ phs[:opt][:auto_sym_vals] = true
37
+ end
38
+ end
39
+
40
+ ##
41
+ # true key
42
+ #
43
+ def self.key_to_true(phs)
44
+ x = []
45
+ x << phs[:opt][:auto_true].is_a?(TrueClass)
46
+ x << phs[:opt][:auto_true_keys].is_a?(TrueClass)
47
+ if x.any?
48
+ case
49
+ when (phs[:key].to_s.strip == "true"): phs[:key] = true
50
+ when (phs[:key].to_s.strip == "false"): phs[:key] = false
51
+ end
52
+ end
53
+ end
54
+
55
+ ##
56
+ # true val
57
+ #
58
+ def self.val_to_true(phs)
59
+ x = []
60
+ x << phs[:opt][:auto_true].is_a?(TrueClass)
61
+ x << phs[:opt][:auto_true_vals].is_a?(TrueClass)
62
+ if x.any?
63
+ case
64
+ when (phs[:val].to_s.strip == "true"): phs[:val] = true
65
+ when (phs[:val].to_s.strip == "false"): phs[:val] = false
66
+ end
67
+ end
68
+ end
69
+
70
+ ##
71
+ # symbolize key
72
+ #
73
+ def self.key_to_sym(phs)
74
+ x = []
75
+ is_str = (phs[:key] =~ /^\d*$/).nil?
76
+ x << phs[:opt][:symbolize].is_a?(TrueClass)
77
+ x << (phs[:ask] && phs[:opt][:auto_sym_keys] && is_str).is_a?(TrueClass)
78
+ x << phs[:opt][:symbolize_keys].is_a?(TrueClass)
79
+ phs[:key] = phs[:key].to_sym if x.any?
80
+ end
81
+
82
+ ##
83
+ # symbolize val
84
+ #
85
+ def self.val_to_sym(phs)
86
+ x = []
87
+ is_str = (phs[:val] =~ /^\d*$/).nil?
88
+ x << phs[:opt][:symbolize].is_a?(TrueClass)
89
+ x << (phs[:asv] && phs[:opt][:auto_sym_vals] && is_str).is_a?(TrueClass)
90
+ x << phs[:opt][:symbolize_vals].is_a?(TrueClass)
91
+ phs[:val] = phs[:val].to_sym if x.any? && !phs[:val].to_s.strip.empty?
92
+ end
93
+
94
+ ##
95
+ # key is parsed as string, so try to_i
96
+ #
97
+ def self.key_to_int(phs)
98
+ x = []
99
+ x << phs[:opt][:int].is_a?(TrueClass)
100
+ x << phs[:opt][:int_keys].is_a?(TrueClass)
101
+ phs[:key] = self.string_to_int(phs[:key]) if x.any?
102
+ end
103
+
104
+ ##
105
+ # val is parsed as string, so try to_i
106
+ #
107
+ def self.val_to_int(phs)
108
+ x = []
109
+ x << phs[:opt][:int].is_a?(TrueClass)
110
+ x << phs[:opt][:int_vals].is_a?(TrueClass)
111
+ phs[:val] = self.string_to_int(phs[:val]) if x.any?
112
+ end
113
+
114
+ ##
115
+ # returns int if string is convertable
116
+ #
117
+ def self.string_to_int(string)
118
+ if string.to_i.to_s == string
119
+ string.to_i
120
+ else
121
+ string
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,61 @@
1
+ module Cheeba
2
+ module Reader
3
+ module Node
4
+ #
5
+ # hashpair
6
+ #
7
+ def self.hashpair(hsh, sym, spc)
8
+ /^(#{spc}*)(\S*)#{hsh}#{spc}*(.*)#{spc}*$/
9
+ end
10
+
11
+ #
12
+ # hashpair, both key and val are symbol
13
+ #
14
+ def self.hashpair_sym_all(hsh, sym, spc)
15
+ /^(#{spc}*)(#{sym}\S*)#{hsh}#{spc}*(#{sym}.*)#{spc}*$/
16
+ end
17
+
18
+ #
19
+ # hashpair, key is symbol
20
+ #
21
+ def self.hashpair_sym_key(hsh, sym, spc)
22
+ /^(#{spc}*)(#{sym}\S*)#{hsh}#{spc}*(.*)#{spc}*$/
23
+ end
24
+
25
+ #
26
+ # hashpair, value is symbol
27
+ #
28
+ def self.hashpair_sym_val(hsh, sym, spc)
29
+ /^(#{spc}*)(\S*)#{hsh}#{spc}*(#{sym}.*)#{spc}*$/
30
+ end
31
+
32
+ #
33
+ # hashkey is symbol
34
+ #
35
+ def self.hashkey_sym(hsh, sym, spc)
36
+ /^(#{spc}*)(#{sym}\S*)#{hsh}#{spc}*$/
37
+ end
38
+
39
+ #
40
+ # hashkey is awesome
41
+ #
42
+ def self.hashkey(hsh, spc)
43
+ /^(#{spc}*)(\S*)#{hsh}#{spc}*$/
44
+ end
45
+
46
+ #
47
+ # docstart and docterm
48
+ #
49
+ def self.document(idc, spc)
50
+ /^#{spc}*#{idc}#{spc}*$/
51
+ end
52
+
53
+ #
54
+ # comments and arrays
55
+ #
56
+ def self.left_match(idc, spc)
57
+ /^(#{spc}*)#{idc}(#{spc}*)(.*)#{spc}*$/
58
+ end
59
+ end
60
+ end
61
+ end