-
Notifications
You must be signed in to change notification settings - Fork 1
/
rboxy.rb
194 lines (174 loc) · 5.33 KB
/
rboxy.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
require 'pry'
require "#{File.dirname(__FILE__)}/binders/js/knockout.rb"
require "#{File.dirname(__FILE__)}/binders/css/css.rb"
module Rboxy
#Builder class will be the core HTML generator
#implements the bare rules for generating an HTML element
#or required pieces to form a basic element without any attributes
#other then id
class Builder
attr_accessor :handler
attr_writer :input
attr_reader :css_output, :js_output, :html_output
def initialize obj
@output = {
html: '',
js: '',
css: ''
}
@css_output = ''
@js_output = ''
@html_output = ''
@object_nest = []
@object_index = nil
@object_counter = 0
@object_index_topology = []
@input = obj
@page_fragments = []
@current = {}
@handler = Rboxy::MethodHandler.new
if(@input.instance_of?(String) && File.exist?(@input))
file = File.open(@input, 'rb')
contents = file.read
@input = eval(contents) #should be a jsonish type object
end
end
def build
reset
method_command @input
end
protected
def reset
@css_output = ''
@js_output = ''
@html_output = ''
@current = {}
@object_nest = []
@object_index = nil
@object_counter = 0
@object_index_topology = []
@page_fragments = []
end
def box_tags
%w{ li ul a span div table thead tbody tr td th p }
end
def inline_tags
%w{ input img audio }
end
def default_object
{tag: 'div', id: generate_id }#id can be overwritten
end
#essential keys that non empty objects need for processing
#and should be part of the core object language
def object_keys
[:tag, :has]
end
def generate_id
@object_counter += 1
"objectid_"+ @object_counter.to_s
end
#core command behind the :has tag
#and a key way to write a binder handler as well
def method_command val
t = ''
case val
when String #string can be whatever you want but be careful
t = val#Rboxy::StringInput.handle(val)
when Hash #hash is an html object
@current = default_object.merge(val)
t = make_object
when Array #array just means you have another collection of objects or strings
val.each{|v| t << method_command(v)}
when Boolean
when Integer
end
return t
end
#the object{} to HTML generator that will produce css and js
#and return html to be appended to the html accumulator
def make_object
html_acc = start_object
keys = @current.keys
(keys - object_keys).each do |key|
t = @handler.run(key.to_s, @current[key], @current)
if (t.instance_of?(String) && !t.empty?)#if val is string
html_acc << " #{t}"
else
if t.instance_variable_defined?('@js')
@js_output<< t.js
end
if t.instance_variable_defined?('@html')
html_acc << " #{t.html}"
end
if t.instance_variable_defined?('@css')
@css_output<< t.css
end
end
end
html_acc << close_object
#if nest is empty then string can be returned to final HTML output
if @object_index == nil
@html_output << html_acc
html_acc = ''
end
end
return html_acc
end
#starts the generation of a new HTML object/DOM Element etc.
def start_object
@object_nest << @current
@object_index = (@object_index == nil ? 0 : @object_index + 1)
@object_index_topology << @object_index
start = '<' + @current[:tag]
@page_fragments << start
return start
end
#this is where the magic starts to generate the next nested object
def close_object
#check out the objects collection or HTML children if you will
has = (@current.has_key?(:has) ? method_command(@current[:has]) : '')
output = (!inline_tags.index(@current[:tag]) ? ">#{has}</#{@current[:tag]}>" : " />")
#@object_nest.pop#done with the object so get rid of it
@object_index = (@object_index == 0 ? nil : @object_index - 1)
@current = (@object_index == nil ? {} : @object_nest[@object_index])
@page_fragments << output
return output
end
end
#core class for running non core tags
#can always add new binders to this at runtime
class MethodHandler
attr_accessor :method_list
def initialize
@method_list = {
bind: Rboxy::Binders::Knockout.new,
css: Rboxy::Binders::Css.new
}
end
def method_missing(val, *args)
if(@method_list.key? val)
return @method_list[val.to_sym].run(args[0],args[1])
else
#default match allows one to just define html attributes
#without being interecepeted by a handler
return "#{val.to_s}=\"#{args[0]}\""
end
end
#an alias for send
def run(key,arg,obj)
self.send(key,arg,obj)
end
end
class ParseError; end
end
if(!ARGV.empty? && ($0 == __FILE__))
ARGV.each do |arg|
file = File.open(arg, 'rb')
contents = file.read
v = eval(contents)
t = Rboxy::Builder.new(v)
t.build
puts t.html_output + '<script type="text/javascript">'+t.js_output+'</script>'
end
end