Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
---|---|---|---|---|
lib/bee_context.rb | 201 | 130 | 100.00%
|
100.00%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 # Copyright 2006-2012 Michel Casabianca <michel.casabianca@gmail.com> |
2 # |
3 # Licensed under the Apache License, Version 2.0 (the "License"); |
4 # you may not use this file except in compliance with the License. |
5 # You may obtain a copy of the License at |
6 # |
7 # http://www.apache.org/licenses/LICENSE-2.0 |
8 # |
9 # Unless required by applicable law or agreed to in writing, software |
10 # distributed under the License is distributed on an "AS IS" BASIS, |
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 # See the License for the specific language governing permissions and |
13 # limitations under the License. |
14 |
15 require 'rubygems' |
16 require 'bee_util' |
17 require 'bee_properties' |
18 |
19 module Bee |
20 |
21 # Class for build context where properties live as local variables and where |
22 # all scripts (from context or in Ruby tasks) are evaluated. |
23 class Context |
24 |
25 include Bee::Util::BuildErrorMixin |
26 |
27 # The context binding |
28 attr_reader :context_binding |
29 |
30 # Constructor. |
31 # - properties: properties as a hash that gives expression for a given |
32 # property. |
33 # - scripts: list of script files to run in context. |
34 def initialize(properties={}, scripts=[]) |
35 @context_binding = get_binding |
36 @properties = properties |
37 @scripts = scripts |
38 end |
39 |
40 # Evaluate properties and scripts in the context. Should run while running |
41 # the build, not while loading it. |
42 def evaluate |
43 evaluate_default_properties |
44 evaluate_scripts |
45 evaluate_properties |
46 end |
47 |
48 # Return the list of properties (that is the list of local variables of |
49 # context) as an unsorted list of strings. |
50 def properties |
51 return eval('local_variables', @context_binding).map{|var| var.to_s} |
52 end |
53 |
54 # Set a given property in context. |
55 # - name: the property name as a string or symbol. |
56 # - value: the property value as an object. |
57 def set_property(name, value) |
58 begin |
59 eval("#{name} = #{value.inspect}", @context_binding) |
60 rescue Exception |
61 error "Error setting property '#{name} = #{value.inspect}': #{$!}" |
62 end |
63 end |
64 |
65 # Get a given property in context. Raises an error if the property was not |
66 # set. |
67 # - name: the property name. |
68 def get_property(name) |
69 begin |
70 eval("#{name}", @context_binding) |
71 rescue NameError |
72 error "Property '#{name}' was not set" |
73 rescue Exception |
74 error "Error getting property '#{name}': #{$!}" |
75 end |
76 end |
77 |
78 # Evaluate a script in context. |
79 # - source: source of the script to evaluate. |
80 def evaluate_script(source) |
81 eval(source, @context_binding) |
82 end |
83 |
84 # Process a given object, replacing properties references with their |
85 # string value, symbol with their raw value. Property references have |
86 # same form than variable references in ruby strings: '#{variable}' |
87 # will be replaced with variable string value. |
88 # - object: object to process. |
89 def evaluate_object(object) |
90 case object |
91 when NilClass |
92 # nil: return nil |
93 return nil |
94 when String |
95 # string: replace embedded Ruby expressions |
96 object = object.gsub(/#\{.+?\}/) do |match| |
97 expression = match[2..-2] |
98 begin |
99 value = eval(expression, @context_binding) |
100 rescue |
101 error "Error evaluating expression '#{expression}': #{$!}" |
102 end |
103 value |
104 end |
105 return object |
106 when Symbol |
107 # symbol: return property object |
108 property = object.to_s |
109 begin |
110 value = eval("#{property}", @context_binding) |
111 rescue |
112 error "Property '#{property}' was not set" |
113 end |
114 return evaluate_object(value) |
115 when Array |
116 # array: evaluate each element |
117 return object.collect { |element| evaluate_object(element) } |
118 when Hash |
119 # hash: evaluate all keys and values |
120 evaluated = {} |
121 object.each_pair do |key, value| |
122 evaluated[evaluate_object(key)] = evaluate_object(value) |
123 end |
124 return evaluated |
125 else |
126 return object |
127 end |
128 end |
129 |
130 private |
131 |
132 # Evaluate properties in context, except system properties. |
133 def evaluate_properties |
134 for name in (@properties.keys - Bee::Properties::SYSTEM_PROPERTIES) |
135 begin |
136 Thread.current[:stack] = [] |
137 evaluate_property(name) |
138 ensure |
139 Thread.current[:stack] = nil |
140 end |
141 end |
142 end |
143 |
144 # Evaluate default properties in context. |
145 def evaluate_default_properties |
146 for name in Bee::Properties::SYSTEM_PROPERTIES |
147 begin |
148 Thread.current[:stack] = [] |
149 evaluate_property(name) |
150 ensure |
151 Thread.current[:stack] = nil |
152 end |
153 end |
154 end |
155 |
156 # Evaluate a property with given name. |
157 # - name: the name of the property to evaluate. |
158 def evaluate_property(name) |
159 stack = Thread.current[:stack] |
160 error "Circular properties: #{stack.join(', ')}" if stack.include?(name) |
161 begin |
162 stack.push(name) |
163 value = evaluate_object(@properties[name]) |
164 stack.pop |
165 set_property(name, value) |
166 return value |
167 rescue |
168 error "Error evaluating property '#{name}': #{$!}" |
169 end |
170 end |
171 |
172 # Evaluate scripts in the context. |
173 def evaluate_scripts |
174 for script in @scripts |
175 begin |
176 source = Bee::Util::get_file(script, @base) |
177 evaluate_script(source) |
178 rescue Exception |
179 error "Error loading context '#{script}': #{$!}" |
180 end |
181 end |
182 end |
183 |
184 # Catch missing properties as missing methods. |
185 # - name: the name of the missing property or method. |
186 def method_missing(name, *args, &block) |
187 if Thread.current[:stack] |
188 return evaluate_property(name) |
189 else |
190 raise NoMethodError.new("undefined method `#{name}'", name, args) |
191 end |
192 end |
193 |
194 # Get a binding as script context. |
195 def get_binding |
196 return binding |
197 end |
198 |
199 end |
200 |
201 end |
Generated on Fri Oct 09 02:07:49 +0200 2015 with rcov 1.0.0