aml 0.1.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,201 @@
1
+ # Cluster will have access to all variable and mixin definitions.
2
+ class Cluster
3
+ require "aml/Definition"
4
+ def initialize(files)
5
+ @log = []
6
+ @definition = []
7
+ @cluster = {
8
+ :variables => {},
9
+ :mixins => {}
10
+ }
11
+ files.each do |file|
12
+ @definition << Definition.new(file[:file], file[:type], file[:bundle])
13
+ end
14
+ end
15
+ def process
16
+ @definition.each do |definition|
17
+ definition.log.each do |log|
18
+ @log << log
19
+ end
20
+ process_variable_definition(definition)
21
+ process_mixin_definition(definition)
22
+ end
23
+ end
24
+ def post_process
25
+ definition.each do |definition|
26
+ process_conditional(definition)
27
+ end
28
+ end
29
+ def log
30
+ @log
31
+ end
32
+ def variables
33
+ @cluster[:variables]
34
+ end
35
+ def mixins
36
+ @cluster[:mixins]
37
+ end
38
+ def definition
39
+ @definition
40
+ end
41
+ private
42
+ # Process Variable Definition (Cluster)
43
+ def process_variable_definition(definition)
44
+ definition.self[:variable].each do |bundle, variables|
45
+ bundle = bundle.to_s
46
+ @cluster[:variables][bundle] = {} if @cluster[:variables][bundle] == nil
47
+ variables.each do |variable,lines|
48
+ @cluster[:variables][bundle][variable] = [] if @cluster[:variables][bundle][variable] == nil
49
+ lines.each do |number,value|
50
+ @cluster[:variables][bundle][variable] << {:number=>number, :value=>value}
51
+ end
52
+ end
53
+ end
54
+ end
55
+ # Process Mixin Definition (Cluster)
56
+ def process_mixin_definition(definition)
57
+ definition.self[:mixin].each do |bundle, mixins|
58
+ bundle = bundle.to_s
59
+ @cluster[:mixins][bundle] = {} if @cluster[:mixins][bundle] == nil
60
+ mixins.each do |name, mixin|
61
+ mixin[:structure] = process_conditional_block(definition, _get_conditionals(mixin[:structure]),mixin[:structure],'loop')
62
+ @cluster[:mixins][bundle][name] = mixin
63
+ end
64
+ end
65
+ end
66
+ # Process Conditional (Cluster)
67
+ def process_conditional(definition)
68
+ definition.self[:hash] = process_conditional_block(definition, _get_conditionals(definition.self[:hash]), definition.self[:hash], 'loop')
69
+ definition.self[:hash] = process_conditional_block(definition, _get_conditionals(definition.self[:hash]), definition.self[:hash], 'if')
70
+ end
71
+ # Process Conditional Block
72
+ def process_conditional_block(definition, conditionals, lines, type)
73
+ conditional = conditionals.select{|k|k[:name].downcase == type}.sort_by{|k|k[:index]}.reverse
74
+ if conditional.count > 0
75
+ conditional = conditional.first
76
+ conditional_lines = []
77
+ definition_before = lines[0...(conditional[:c_index]-1)]
78
+ definition_after = lines[conditional[:end][:c_index]..lines.count]
79
+ if type == 'loop'
80
+ if is_number?(conditional[:value])
81
+ for i in 1..conditional[:value].to_i
82
+ value = i.to_s
83
+ loop_line = Marshal.load(Marshal.dump(lines.select{|k|k[:c_index] > conditional[:c_index] and k[:c_index] < conditional[:end][:c_index]}))
84
+ loop_line.each do |line|
85
+ line[:index] = line[:index]-1
86
+ line[:text] = line[:text].gsub(/@@/,value) if line[:text] != nil
87
+ line[:value] = line[:value].gsub(/@@/,value) if line[:value] != nil
88
+ if line[:attribute] != nil
89
+ line[:attribute].each do |attribute|
90
+ line[:attribute][attribute[0]] = attribute[1].gsub(/@@/,value) if attribute[1] != nil
91
+ end
92
+ end
93
+ conditional_lines << line
94
+ end
95
+ end
96
+ else
97
+ conditional[:value].split(',').each do |value|
98
+ value = value.strip
99
+ loop_line = Marshal.load(Marshal.dump(lines.select{|k|k[:c_index] > conditional[:c_index] and k[:c_index] < conditional[:end][:c_index]}))
100
+ loop_line.each do |line|
101
+ line[:index] = line[:index]-1
102
+ line[:text] = line[:text].gsub(/@@/,value) if line[:text] != nil
103
+ line[:value] = line[:value].gsub(/@@/,value) if line[:value] != nil
104
+ if line[:attribute] != nil
105
+ line[:attribute].each do |attribute|
106
+ line[:attribute][attribute[0]] = attribute[1].gsub(/@@/,value) if attribute[1] != nil
107
+ end
108
+ end
109
+ conditional_lines << line
110
+ end
111
+ end
112
+ end
113
+ elsif type == 'if'
114
+ regex = /(?<a>.+?)\s{1,}?(?<expression>==|!=|>=|<=|>|<|eq|neq|gte|lte|gt|lt)\s{1,}?(?<b>.+)/
115
+ match = conditional[:value].to_s.gsub(regex).each do
116
+ continue = false
117
+ if is_number? $1 and is_number? $3
118
+ if ['=','==','eq'].include?($2.to_s.downcase)
119
+ continue = true if $1.to_i == $3.to_i
120
+ elsif ['!=','neq'].include?($2.to_s.downcase)
121
+ continue = true if $1.to_i != $3.to_i
122
+ elsif ['>=','gte'].include?($2.to_s.downcase)
123
+ continue = true if $1.to_i >= $3.to_i
124
+ elsif ['<=','lte'].include?($2.to_s.downcase)
125
+ continue = true if $1.to_i <= $3.to_i
126
+ elsif ['>','gt'].include?($2.to_s.downcase)
127
+ continue = true if $1.to_i > $3.to_i
128
+ elsif ['<','lt'].include?($2.to_s.downcase)
129
+ continue = true if $1.to_i < $3.to_i
130
+ end
131
+ else
132
+ if ['=','==','eq'].include?($2.to_s.downcase)
133
+ continue = true if $1.to_s == $3.to_s
134
+ elsif ['!=','neq'].include?($2.to_s.downcase)
135
+ continue = true if $1.to_s != $3.to_s
136
+ end
137
+ end
138
+ conditional_lines = Marshal.load(Marshal.dump(lines.select{|k|k[:c_index] > conditional[:c_index] and k[:c_index] < conditional[:end][:c_index]})) if continue
139
+ conditional_lines.each do |line|
140
+ line[:index] = line[:index]-1
141
+ end
142
+ end
143
+ end
144
+ lines = definition_before.concat(conditional_lines).concat(definition_after)
145
+ conditionals = _get_conditionals(lines)
146
+ lines = process_conditional_block(definition,conditionals,lines, type) if conditionals.select{|k|k[:name].downcase == type}.count > 0
147
+ end
148
+ lines
149
+ end
150
+
151
+ def is_number?(value)
152
+ value.to_f.to_s == value.to_s || value.to_i.to_s == value.to_s
153
+ end
154
+
155
+ # Get Conditionals
156
+ def _get_conditionals(lines)
157
+ conditional_line = []
158
+ conditional_block = []
159
+ condition_open = 0
160
+ condition_index = 0
161
+ last_line = false
162
+ lines.each_with_index do |line,index|
163
+ line[:c_index] = index + 1
164
+ end
165
+ lines.select{|k|k[:type] == :conditional}.each do |line|
166
+ if line[:name].downcase != 'end'
167
+ condition_open = condition_open + 1
168
+ else
169
+ condition_open = condition_open - 1
170
+ end
171
+ conditional_block[condition_index] = [] if conditional_block[condition_index] == nil
172
+ conditional_block[condition_index] << line
173
+ condition_index = condition_index + 1 if condition_open == 0
174
+ end
175
+ conditional = []
176
+ conditional_block.each do |block|
177
+ block_open = block.select{|k|k[:name].downcase != 'end'}
178
+ block_close = block.select{|k|k[:name].downcase == 'end'}
179
+ close_block = []
180
+ count = 0
181
+ block_close.each_with_index do |close, index|
182
+ if close_block.count == 0
183
+ close_block << close
184
+ else
185
+ if close_block[index-1][:index] == close[:index]
186
+ close_block.insert(index-1-count, close)
187
+ count += 1
188
+ else
189
+ close_block << close
190
+ end
191
+ end
192
+ end
193
+ close_block = close_block.reverse
194
+ block_open.each_with_index do |line, index|
195
+ line[:end] = {:c_index=>close_block[index][:c_index], :value=> close_block[index][:value]}
196
+ conditional << line
197
+ end
198
+ end
199
+ conditional
200
+ end
201
+ end
@@ -0,0 +1,217 @@
1
+ class Compile
2
+ require "aml/Prepare"
3
+ def initialize(argument)
4
+ @argument = argument
5
+ file = @argument.get('build')
6
+ @prepare = Prepare.new(file)
7
+ @inline = [
8
+ {:type=> :attribute, :regex=> /@\(\:(?<name>[\w|\-]+)\)/},
9
+ {:type=> :method, :regex=> /::((?<bundle>[\w|\-]+)\.)?(?<name>[\w|\-]+)(\{(?<attribute>.+)\})?/},
10
+ {:type=> :variable, :regex=> /\@\(((?<bundle>[\w|\-]+)\.)?(?<name>[\w|\-]+)\)/}
11
+ ]
12
+ @prepare.cluster.variables['false'] = {} if @prepare.cluster.variables.include?('false') == false
13
+ local = [
14
+ {:name=> 'file-created', :value=> Time.new.strftime('%Y-%m-%d %H:%M:%S')},
15
+ {:name=> 'file-name', :value=> File.basename(file)},
16
+ {:name=> 'file-path', :value=> File.expand_path(file)}
17
+ ].each do |variable|
18
+ @prepare.cluster.variables['false'][variable[:name].to_s] = [{:number=>0, :value=>variable[:value].to_s}]
19
+ end
20
+
21
+ @log = []
22
+
23
+ @prepare.log.each do |log|
24
+ if log[:type] == "mixin"
25
+ @log << log if log[:bundle] != false
26
+ else
27
+ @log << log
28
+ end
29
+ end
30
+
31
+
32
+ if @log.count == 0
33
+ process
34
+ @prepare.cluster.post_process
35
+ end
36
+
37
+ end
38
+ def log
39
+ @log
40
+ end
41
+ def structure
42
+ @prepare.cluster.definition.select{|k|k.self[:type] == "base"}.first.self[:hash]
43
+ end
44
+ def process
45
+ @prepare.cluster.definition.each do |definition|
46
+ definition.self[:hash].each_with_index do |line, index|
47
+ process_variable_and_method(line, index, definition)
48
+ process_mixin(line, index, definition)
49
+ process_partial(line, index, definition)
50
+ end
51
+ end
52
+ process if @prepare.cluster.definition.select{|k|k.self[:type] == "base"}.first.self[:hash].select{|k|k[:type] == :mixin or k[:type] == :partial}.count > 0
53
+ end
54
+ def post_process
55
+ @prepare.cluster.definition.each do |definition|
56
+ definition.self[:hash].each_with_index do |line, index|
57
+ process_variable_and_method(line, index, definition, true)
58
+ end
59
+ end
60
+ end
61
+ private
62
+ def has_match?(string, regex)
63
+ return string.to_s.match(regex) != nil
64
+ end
65
+ def process_variable_and_method(line, index, definition, methods=false)
66
+ definition.self[:hash][index] = process_variable_line(line, definition)
67
+ definition.self[:hash][index] = process_method_line(line, definition) if methods
68
+ end
69
+ def process_variable_line(line, definition)
70
+ if line[:type] == :string
71
+ line[:value] = process_variable_find(line[:value], line, definition)
72
+ parse = Parse.new(definition.self[:bundle])
73
+ line = parse.line("#{"\t" * line[:index]}#{line[:value]}",line[:number])
74
+ else
75
+ line[:text] = process_variable_find(line[:text], line, definition)
76
+ line[:value] = process_variable_find(line[:value], line, definition)
77
+ if line.key? :attribute != nil
78
+ line[:attribute].each do|k,v|
79
+ line[:attribute][k] = process_variable_find(v, line, definition)
80
+ end
81
+ end
82
+ end
83
+ line
84
+ end
85
+ def process_method_line(line, definition)
86
+ if line[:type] == :string
87
+ line[:value] = process_method_find(line[:value], line)
88
+ parse = Parse.new(definition.self[:bundle])
89
+ line = parse.line("#{"\t" * line[:index]}#{line[:value]}",line[:number])
90
+ else
91
+ line[:text] = process_method_find(line[:text], line)
92
+ if line.key? :attribute != nil
93
+ line[:attribute].each do|k,v|
94
+ line[:attribute][k] = process_method_find(v, line)
95
+ end
96
+ end
97
+ end
98
+ line
99
+ end
100
+ def process_variable_find(string, line, definition)
101
+ regex = @inline.select{|k|k[:type] == :variable}[0][:regex]
102
+ string = string.to_s.gsub(regex).each do
103
+ process_variable_replace($1, $2, line[:number], definition)
104
+ end
105
+ string = process_variable_find(string, line, definition) if has_match?(string, regex)
106
+ return string
107
+ end
108
+ def process_method_find(string, line)
109
+ regex = @inline.select{|k|k[:type] == :method}[0][:regex]
110
+ string = string.to_s.gsub(regex).each do
111
+ process_method_replace($1, $2, $3, line[:index])
112
+ end
113
+ string = process_method_find(string, line) if has_match?(string, regex)
114
+ return string
115
+ end
116
+ def process_variable_replace(bundle, name, number, definition)
117
+ bundle = false.to_s if bundle == nil
118
+ number = 0 if bundle != "false"
119
+ begin
120
+ @prepare.cluster.variables.reject{|k| k != bundle}.first.last.reject{|k| k != name}.first.last.select{|k| if number != 0 then k[:number] < number else k[:number] == k[:number] end}.last[:value]
121
+ rescue
122
+ @log << {:fail=>false, :file=>definition.self[:file], :bundle=>definition.self[:bundle], :line=>number, :message=>"#{bundle.to_s != false.to_s ? bundle+"." : nil}#{name} variable does not exist; ignored."}
123
+ return nil
124
+ end
125
+ end
126
+ def process_method_replace(bundle, name, attribute, index)
127
+ bundle = 'core' if bundle == nil
128
+ begin
129
+ file = bundle == 'core' ? File.join(File.dirname(File.expand_path(__FILE__)),'core','method.rb') : File.join(File.dirname(File.expand_path(definition.self[:file])),line[:bundle],'method.rb')
130
+ Compile.class_eval File.read(file)
131
+ method_attribute = Line.new(bundle, :string, @inline.select{|k|k[:type] == :method}[0][:regex])
132
+ method_attribute = method_attribute.match?("::#{bundle}.#{name}{#{attribute}}", index)
133
+ attribute = method_attribute[:attribute]
134
+ Compile.const_get(bundle.split('-').map{|k|k.capitalize}.join).method(name).call(index, attribute)
135
+ rescue
136
+ return nil
137
+ end
138
+ end
139
+ def process_mixin(line, index, definition)
140
+ if line[:type] == :mixin
141
+ definition.self[:hash].delete_at index
142
+ mixin = process_mixin_find(line, line[:index], definition)
143
+ if mixin.is_a? Hash
144
+ mixin[:structure].each_with_index do |mixin_line, mixin_index|
145
+ definition.self[:hash].insert(index+mixin_index, mixin_line)
146
+ end
147
+ else
148
+ @log << {:fail=>false, :file=>definition.self[:file], :bundle=>definition.self[:bundle], :line=>line[:number], :message=>"#{line[:bundle] ? line[:bundle]+ '.' : nil}#{line[:name]} mixin does not exist; ignored."}
149
+ end
150
+ end
151
+ end
152
+ def process_mixin_find(line, offset=0, definition)
153
+ begin
154
+ mixin = Marshal.load(Marshal.dump(@prepare.cluster.mixins.reject{|k|k != line[:bundle].to_s}.first.last.reject{|k|k != line[:name]}.first.last))
155
+ mixin[:attribute] = mixin[:attribute].merge(line[:attribute])
156
+ mixin[:attribute].each do |attribute, value|
157
+ mixin[:attribute][attribute] = process_variable_find(value, line, definition)
158
+ end
159
+ mixin[:structure].each do |mixin_line|
160
+ mixin_line[:index] += offset
161
+ mixin_line[:number] = line[:number]
162
+ mixin_line = process_attribute(mixin_line, mixin)
163
+ mixin_line = process_variable_line(mixin_line, definition)
164
+ end
165
+ return mixin
166
+ rescue
167
+ return false
168
+ end
169
+ end
170
+ def process_attribute(line, mixin)
171
+ if line[:type] == :string
172
+ line[:value] = process_attribute_find(line[:value], mixin[:attribute])
173
+ else
174
+ line[:text] = process_attribute_find(line[:text], mixin[:attribute])
175
+ if line[:attribute] != nil
176
+ line[:attribute].each do|k,v|
177
+ line[:attribute][k] = process_attribute_find(v, mixin[:attribute])
178
+ end
179
+ end
180
+ end
181
+ line
182
+ end
183
+ def process_attribute_find(string, attribute)
184
+ regex = @inline.select{|k|k[:type] == :attribute}[0][:regex]
185
+ string = string.to_s.gsub(regex).each do
186
+ attribute[$1.to_sym].to_s
187
+ end
188
+ string = process_attribute_find(string,attribute) if has_match?(string, regex)
189
+ return string
190
+ end
191
+ def process_partial(line, index, definition)
192
+ if line[:type] == :partial
193
+ definition.self[:hash].delete_at index
194
+ partial = process_partial_find(line, line[:index], definition)
195
+ if partial.is_a? Array
196
+ partial.each_with_index do |partial_line,partial_index|
197
+ definition.self[:hash].insert(index+partial_index,partial_line)
198
+ end
199
+ end
200
+ end
201
+ end
202
+ def process_partial_find(line, offset, definition)
203
+ path = line[:bundle].to_s == false.to_s ? "partial" : line[:bundle].to_s
204
+ partial_number = line[:number]
205
+ patrial_attribute = line[:attribute]
206
+ partial = Definition.new(File.join(@argument.get('path'),path,line[:name]+'.aml'), line[:type].to_s, line[:bundle])
207
+ partial.self[:hash].each_with_index do |line, index|
208
+ line[:number] = partial_number
209
+ line = process_attribute(line, {:attribute=>patrial_attribute})
210
+ line = process_variable_line(line, definition)
211
+ end
212
+ partial.self[:hash].each do|line|
213
+ line[:index] += offset
214
+ end
215
+ partial.self[:hash]
216
+ end
217
+ end
@@ -0,0 +1,71 @@
1
+ class Definition
2
+ require "aml/Parse"
3
+ def initialize(file, type, bundle=false)
4
+ @log = []
5
+ @definition = {}
6
+ @definition[:file] = file
7
+ @definition[:type] = type
8
+ @definition[:bundle] = bundle
9
+ @definition[:hash] = []
10
+ @definition[:variable] = {}
11
+ @definition[:mixin] = {}
12
+ number = 0
13
+ begin
14
+ parse = Parse.new(bundle)
15
+ # Remove Comment Line(s)
16
+ File.open(file).read.gsub(/%!--[^%]*--%$/,'').each_line do |line|
17
+ number+=1
18
+ # Remove Empty Lines
19
+ add_line(parse.line(line,number))
20
+ end
21
+ process_variable_definition
22
+ process_mixin_definition
23
+
24
+ rescue Exception => e
25
+ @log << {:fail=>true, :file=>@definition[:file], :type=>@definition[:type], :bundle=> bundle, :message=>'file does not exist.'}
26
+ false
27
+ end
28
+ end
29
+ def log
30
+ @log
31
+ end
32
+ def self
33
+ @definition
34
+ end
35
+ private
36
+ def add_line(line)
37
+ @definition[:hash] << line if line[:type] != :empty
38
+ end
39
+ # Process Variable Definition (Local)
40
+ def process_variable_definition
41
+ @definition[:hash].reject{|k,v| k[:type] != :variable_definition}.each do |variable|
42
+ variable[:bundle] = variable[:bundle].to_s
43
+ @definition[:variable][variable[:bundle]] = {} if @definition[:variable].has_key?(variable[:bundle]) == false
44
+ @definition[:variable][variable[:bundle]][variable[:name]] = {} if @definition[:variable][variable[:bundle]].has_key?(variable[:name]) == false
45
+ @definition[:variable][variable[:bundle]][variable[:name]][variable[:number]] = variable[:value]
46
+ end
47
+ @definition[:hash] = @definition[:hash].reject{|k,v| k[:type] == :variable_definition}
48
+ end
49
+ # Process Mixin Definition (Local)
50
+ def process_mixin_definition
51
+ mixin_definition = @definition[:hash].reject{|k|k[:type] != :mixin_definition}
52
+ mixin_definition_end = @definition[:hash].reject{|k|k[:type] != :mixin_end}
53
+ if mixin_definition.count == mixin_definition_end.count
54
+ mixin_definition.each_with_index do |mixin,index|
55
+ @definition[:mixin][@definition[:bundle]] = {} if @definition[:mixin].has_key?(@definition[:bundle]) == false
56
+ if @definition[:mixin][@definition[:bundle]].has_key?(mixin[:name]) == false
57
+ @definition[:mixin][@definition[:bundle]][mixin[:name]] = {
58
+ :attribute => mixin[:attribute],
59
+ :structure => @definition[:hash].reject{|k,v| k[:number].between?(mixin[:number]+1,mixin_definition_end[index][:number]-1) == false}
60
+ }
61
+ @definition[:mixin][@definition[:bundle]][mixin[:name]][:structure].each do |line|
62
+ line[:index]-=1
63
+ end
64
+ else
65
+ @log << {:fail=>false, :file=>@definition[:file], :bundle=>@definition[:bundle], :line=>mixin[:number], :message=>"#{mixin[:name]} duplicate mixin definition; ignored."}
66
+ end
67
+ @definition[:hash] = @definition[:hash].reject{|k,v| k[:number].between?(mixin[:number],mixin_definition_end[index][:number])}
68
+ end
69
+ end
70
+ end
71
+ end