awesome-cheeba 1.0.1

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