aml 0.1.1.1 → 0.1.2

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,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