EFL 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/README.txt +36 -0
  2. data/lib/EFL.rb +494 -0
  3. data/lib/EFL_array.rb +20 -0
  4. data/lib/EFL_errors.rb +48 -0
  5. data/lib/EFL_hash.rb +18 -0
  6. data/lib/EFL_production.rb +49 -0
  7. data/lib/EFL_regexp.rb +112 -0
  8. data/lib/EFL_regexp_generator.rb +70 -0
  9. data/lib/EFL_substitution.rb +221 -0
  10. data/lib/EFL_syntactic_sugar.rb +67 -0
  11. data/lib/Hash Doc.doc +0 -0
  12. data/lib/Limitaciones.txt +3 -0
  13. data/lib/doc/classes/Generator.html +634 -0
  14. data/lib/doc/classes/Generator.src/M000008.html +18 -0
  15. data/lib/doc/classes/Generator.src/M000009.html +18 -0
  16. data/lib/doc/classes/Generator.src/M000010.html +18 -0
  17. data/lib/doc/classes/Generator.src/M000011.html +18 -0
  18. data/lib/doc/classes/Generator.src/M000012.html +18 -0
  19. data/lib/doc/classes/Generator.src/M000013.html +18 -0
  20. data/lib/doc/classes/Generator.src/M000014.html +18 -0
  21. data/lib/doc/classes/Generator.src/M000015.html +18 -0
  22. data/lib/doc/classes/Generator.src/M000016.html +28 -0
  23. data/lib/doc/classes/Generator.src/M000017.html +24 -0
  24. data/lib/doc/classes/Generator.src/M000018.html +157 -0
  25. data/lib/doc/classes/Generator.src/M000019.html +25 -0
  26. data/lib/doc/classes/Generator.src/M000020.html +30 -0
  27. data/lib/doc/classes/Generator.src/M000021.html +32 -0
  28. data/lib/doc/classes/Generator.src/M000022.html +22 -0
  29. data/lib/doc/classes/Generator.src/M000023.html +18 -0
  30. data/lib/doc/classes/Generator.src/M000024.html +27 -0
  31. data/lib/doc/classes/Generator.src/M000025.html +22 -0
  32. data/lib/doc/classes/Generator.src/M000026.html +18 -0
  33. data/lib/doc/classes/Generator.src/M000027.html +27 -0
  34. data/lib/doc/classes/Regexp.html +271 -0
  35. data/lib/doc/classes/Regexp.src/M000028.html +37 -0
  36. data/lib/doc/classes/Regexp.src/M000029.html +29 -0
  37. data/lib/doc/classes/Regexp.src/M000030.html +32 -0
  38. data/lib/doc/created.rid +1 -0
  39. data/lib/doc/files/EFL_rb.html +147 -0
  40. data/lib/doc/files/EFL_regexp_generator_rb.html +242 -0
  41. data/lib/doc/files/EFL_regexp_generator_rb.src/M000003.html +27 -0
  42. data/lib/doc/files/EFL_regexp_generator_rb.src/M000004.html +27 -0
  43. data/lib/doc/files/EFL_regexp_generator_rb.src/M000005.html +19 -0
  44. data/lib/doc/files/EFL_regexp_generator_rb.src/M000006.html +20 -0
  45. data/lib/doc/files/EFL_regexp_generator_rb.src/M000007.html +19 -0
  46. data/lib/doc/files/EFL_regexp_rb.html +139 -0
  47. data/lib/doc/files/EFL_syntactic_sugar_rb.html +208 -0
  48. data/lib/doc/files/EFL_syntactic_sugar_rb.src/M000001.html +29 -0
  49. data/lib/doc/files/EFL_syntactic_sugar_rb.src/M000002.html +19 -0
  50. data/lib/doc/fr_class_index.html +28 -0
  51. data/lib/doc/fr_file_index.html +30 -0
  52. data/lib/doc/fr_method_index.html +56 -0
  53. data/lib/doc/index.html +24 -0
  54. data/tests/Add_Sup_1.rb +223 -0
  55. data/tests/Add_Sup_1.rb.bak +223 -0
  56. data/tests/Add_Sup_1_NI.rb +25 -0
  57. data/tests/Add_Sup_2.rb +142 -0
  58. data/tests/Add_Sup_2.rb.bak +140 -0
  59. data/tests/All.rb +2 -0
  60. data/tests/All_1.rb +7 -0
  61. data/tests/All_2.rb +7 -0
  62. data/tests/All_2.rb.bak +5 -0
  63. data/tests/BeforeAfter.rb +83 -0
  64. data/tests/Bloques.rb +34 -0
  65. data/tests/Bloques.rb.bak +34 -0
  66. data/tests/Complementary.rb +144 -0
  67. data/tests/ComplementaryZoom.rb +78 -0
  68. data/tests/Del.rb +126 -0
  69. data/tests/Dup.rb +55 -0
  70. data/tests/Dup.rb.bak +54 -0
  71. data/tests/Error.rb +11 -0
  72. data/tests/ErrorArgClass.rb +169 -0
  73. data/tests/ErrorArgClass.rb.bak +158 -0
  74. data/tests/ErrorCollision.rb +218 -0
  75. data/tests/ErrorCollision.rb.bak +219 -0
  76. data/tests/ErrorWithoutDeclaration.rb +60 -0
  77. data/tests/ErrorWithoutDeclaration.rb.bak +60 -0
  78. data/tests/Extract.rb +56 -0
  79. data/tests/ExtractDollar.rb +17 -0
  80. data/tests/HashTest.rb +54 -0
  81. data/tests/HashTest.rb.bak +54 -0
  82. data/tests/Lista Czarnecki/AntiguaInterfaz/List.cpp +75 -0
  83. data/tests/Lista Czarnecki/AntiguaInterfaz/ListTransformer.rb +69 -0
  84. data/tests/Lista Czarnecki/AntiguaInterfaz/ListTransformer.rb.bak +100 -0
  85. data/tests/Lista Czarnecki/AntiguaInterfaz/ejecutame.bat +1 -0
  86. data/tests/Lista Czarnecki/AntiguaInterfaz/outDir/MyClassList.cpp +75 -0
  87. data/tests/Lista Czarnecki/AntiguaInterfaz/runme.bat +1 -0
  88. data/tests/Lista Czarnecki/AntiguaInterfaz/specification1.txt +5 -0
  89. data/tests/Lista Czarnecki/AntiguaInterfaz/specification2.txt +3 -0
  90. data/tests/Lista Czarnecki/AntiguaInterfaz/specification3.txt +5 -0
  91. data/tests/Lista Czarnecki/NuevaInterfaz/List.cpp +75 -0
  92. data/tests/Lista Czarnecki/NuevaInterfaz/ListTransformer.rb +58 -0
  93. data/tests/Lista Czarnecki/NuevaInterfaz/ListTransformer.rb.bak +57 -0
  94. data/tests/Lista Czarnecki/NuevaInterfaz/ejecutame.bat +1 -0
  95. data/tests/Lista Czarnecki/NuevaInterfaz/outDir/MyClassList.cpp +75 -0
  96. data/tests/Lista Czarnecki/NuevaInterfaz/outDir/NewClassList.cpp +75 -0
  97. data/tests/Lista Czarnecki/NuevaInterfaz/specification1.txt +5 -0
  98. data/tests/Lista Czarnecki/NuevaInterfaz/specification1.txt.bak +5 -0
  99. data/tests/Lista Czarnecki/NuevaInterfaz/specification2.txt +3 -0
  100. data/tests/Lista Czarnecki/NuevaInterfaz/specification3.txt +5 -0
  101. data/tests/Minus.rb +89 -0
  102. data/tests/Plus.rb.bak +48 -0
  103. data/tests/REVit.rb +84 -0
  104. data/tests/RenameTest.rb +46 -0
  105. data/tests/RenameTest.rb.bak +46 -0
  106. data/tests/SubCrash.rb +26 -0
  107. data/tests/SubList.rb.bak +43 -0
  108. data/tests/archAuxiliares/1.txt +328 -0
  109. data/tests/archAuxiliares/2.txt +328 -0
  110. data/tests/archAuxiliares/Bloques/s1.txt +328 -0
  111. data/tests/archAuxiliares/Copia de Matriz.java +19 -0
  112. data/tests/archAuxiliares/Gen/Tesis_156_1.lgi +10 -0
  113. data/tests/archAuxiliares/Gen/Tesis_156_2.lgi +10 -0
  114. data/tests/archAuxiliares/Gen/t01.txt +328 -0
  115. data/tests/archAuxiliares/Gen/t01.txt.bak +328 -0
  116. data/tests/archAuxiliares/Gen/t02.txt +328 -0
  117. data/tests/archAuxiliares/Gen/t02.txt.bak +328 -0
  118. data/tests/archAuxiliares/Gen/t03.txt +328 -0
  119. data/tests/archAuxiliares/Gen/t03.txt.bak +328 -0
  120. data/tests/archAuxiliares/Gen/t04.txt +328 -0
  121. data/tests/archAuxiliares/Gen/t04.txt.bak +328 -0
  122. data/tests/archAuxiliares/Gen/t1.txt +328 -0
  123. data/tests/archAuxiliares/Gen/t1.txt.bak +328 -0
  124. data/tests/archAuxiliares/Gen/t2.txt +328 -0
  125. data/tests/archAuxiliares/Gen/t2.txt.bak +328 -0
  126. data/tests/archAuxiliares/Gen/t5.txt +328 -0
  127. data/tests/archAuxiliares/Gen/t9.txt +328 -0
  128. data/tests/archAuxiliares/Gen/t9.txt.bak +328 -0
  129. data/tests/archAuxiliares/GenTesis_156_1.lgi +10 -0
  130. data/tests/archAuxiliares/Matriz.java +74 -0
  131. data/tests/archAuxiliares/MatrizOut.java +74 -0
  132. data/tests/archAuxiliares/MatrizOut10.java +68 -0
  133. data/tests/archAuxiliares/MatrizOut11.java +86 -0
  134. data/tests/archAuxiliares/MatrizOut2.java +74 -0
  135. data/tests/archAuxiliares/MatrizOut3.java +74 -0
  136. data/tests/archAuxiliares/MatrizOut4.java +74 -0
  137. data/tests/archAuxiliares/MatrizOut5.java +21 -0
  138. data/tests/archAuxiliares/MatrizOut6.java +21 -0
  139. data/tests/archAuxiliares/MatrizOut7.java +21 -0
  140. data/tests/archAuxiliares/MatrizOut8.java +16 -0
  141. data/tests/archAuxiliares/MatrizOut9.java +86 -0
  142. data/tests/archAuxiliares/MatrizOut_9.java +86 -0
  143. data/tests/archAuxiliares/Matriz_1.java +74 -0
  144. data/tests/archAuxiliares/Matriz_10.java +68 -0
  145. data/tests/archAuxiliares/Matriz_11.java +86 -0
  146. data/tests/archAuxiliares/Matriz_2.java +74 -0
  147. data/tests/archAuxiliares/Matriz_3.java +74 -0
  148. data/tests/archAuxiliares/Matriz_4.java +74 -0
  149. data/tests/archAuxiliares/Matriz_5.java +21 -0
  150. data/tests/archAuxiliares/Matriz_6.java +21 -0
  151. data/tests/archAuxiliares/Matriz_7.java +21 -0
  152. data/tests/archAuxiliares/Matriz_8.java +16 -0
  153. data/tests/archAuxiliares/Matriz_9.java +86 -0
  154. data/tests/archAuxiliares/Matriz_N_1.java +21 -0
  155. data/tests/archAuxiliares/Matriz_N_2.java +91 -0
  156. data/tests/archAuxiliares/N1.txt +18 -0
  157. data/tests/archAuxiliares/N1_EXPECTED.txt +18 -0
  158. data/tests/archAuxiliares/N1_OUT.txt +18 -0
  159. data/tests/archAuxiliares/N2_EXPECTED.txt +18 -0
  160. data/tests/archAuxiliares/N2_OUT.txt +18 -0
  161. data/tests/archAuxiliares/N3.txt +23 -0
  162. data/tests/archAuxiliares/N3_EXPECTED.txt +22 -0
  163. data/tests/archAuxiliares/N3_OUT.txt +22 -0
  164. data/tests/archAuxiliares/N4_EXPECTED.txt +10 -0
  165. data/tests/archAuxiliares/N4_OUT.txt +10 -0
  166. data/tests/archAuxiliares/N5_OUT.txt +18 -0
  167. data/tests/archAuxiliares/N6_OUT.txt +18 -0
  168. data/tests/archAuxiliares/PedidorTerceroWS.jsp +142 -0
  169. data/tests/archAuxiliares/Tesis_156.lgi +7 -0
  170. data/tests/archAuxiliares/aspectgen.rb +328 -0
  171. data/tests/archAuxiliares/aspectgenCopy.rb +328 -0
  172. data/tests/archAuxiliares/extract_dollar.txt +1 -0
  173. data/tests/archAuxiliares/minus.txt +26 -0
  174. data/tests/archAuxiliares/minus_expected_1.txt +26 -0
  175. data/tests/archAuxiliares/minus_expected_2.txt +26 -0
  176. data/tests/archAuxiliares/minus_out_1.txt +26 -0
  177. data/tests/archAuxiliares/minus_out_2.txt +26 -0
  178. data/tests/archAuxiliares/p1.txt +328 -0
  179. data/tests/archAuxiliares/p2.txt +328 -0
  180. data/tests/archAuxiliares/s1.txt +328 -0
  181. data/tests/archAuxiliares/s2.txt +328 -0
  182. data/tests/archAuxiliares/s3.txt +328 -0
  183. data/tests/archAuxiliares/s4.txt +328 -0
  184. data/tests/archAuxiliares/s5.txt +328 -0
  185. data/tests/archAuxiliares/s7.txt +328 -0
  186. data/tests/archAuxiliares/s8.txt +328 -0
  187. data/tests/archAuxiliares/s9.txt +328 -0
  188. data/tests/archAuxiliares/text.txt +1 -0
  189. data/tests/delay.rb +33 -0
  190. data/tests/delay.rb.bak +33 -0
  191. data/tests/satisfy.rb +44 -0
  192. data/tests/satisfy.rb.bak +34 -0
  193. metadata +252 -0
@@ -0,0 +1,328 @@
1
+ # Author:: Ruben Heradio Gil (mailto:rheradio@lsi.uned.es)
2
+
3
+ #Auxiliar AspectGen class that represents a Pointcut
4
+ class Pointcut < Regexp
5
+ #Pointcut name (a String)
6
+ attr_accessor :name
7
+ #Pointcut value (a Regexp)
8
+ attr_accessor :regExp
9
+ #Pointcut scope ('local' or 'global')
10
+ attr_accessor :scope
11
+
12
+ # * 'name' = Pointcut name (a String)
13
+ # * 'regExp' = Pointcut value (a Regexp)
14
+ # * 'scope' = Pointcut scope ('local' or 'global')
15
+ def constructor(name, regExp, scope='local')
16
+ raise "First argument of Pointcut constructor must be a String" if !name.kind_of?(String)
17
+ raise "Second argument of Pointcut constructor must be a Regular Expression" if !regExp.kind_of?(Regexp)
18
+ raise "Pointcut scope must be 'local' or 'global'" if (scope != 'local') and
19
+ (scope != 'global')
20
+ super(regExp)
21
+ @name = name
22
+ @regExp = regExp
23
+ @scope = scope
24
+ end #constructor
25
+
26
+ def clone
27
+ result = Pointcut.new(@name.clone, @regExp.clone, @scope.clone)
28
+ end #clone
29
+
30
+ #Determine if two Pointcuts ('self' and 'pointcut') applied over the same input file ('fin') go colisi�n
31
+ def colisi�n?(pointcut, fin)
32
+
33
+ raise "First argument of Pointcut#colisi�n? must be a Pointcut" if !pointcut.kind_of?(Pointcut)
34
+ # colisi�n? inner auxiliar method that determines if two local Pointcuts ('pointcut1' and 'pointcut2') applied over the String tr' go colisi�n
35
+ def colisi�nAux1?(pointcut1, pointcut2, str)
36
+ position1 = str =~ pointcut1
37
+ match1 = $&
38
+ position2 = str =~ pointcut2
39
+ match2 = $&
40
+ return false if (position1 == nil) or (position2 == nil)
41
+ if (position1 <= position2)
42
+ return true if (position1 + match1.length - 1) >= position2
43
+ else
44
+ return true if (position2 + match2.length - 1) >= position1
45
+ end #if
46
+ return false
47
+ end #colisi�nAux1?
48
+
49
+ # colisi�n? inner auxiliar method that determines if a global Pointcut ('globalPointcut') and a local
50
+ # Pointcut ('localPointcut') applied over the String tr' go colisi�n
51
+ def colisi�nAux2?(globalPointcut, localPointcut, str)
52
+ colisi�n = false
53
+ while (str.index(globalPointcut) != nil) and (colisi�n == false)
54
+ colisi�n = colisi�nAux1?(globalPointcut, localPointcut, str)
55
+ str =~ globalPointcut
56
+ str = $'
57
+ end #while
58
+ return colisi�n
59
+ end
60
+
61
+ colisi�n = false
62
+ File.open(fin) { |f|
63
+ fcode = f.read
64
+ if (self.scope == 'local') and (pointcut.scope == 'local')
65
+ colisi�n = colisi�nAux1?(self, pointcut, fcode)
66
+ elsif (self.scope == 'local') and (pointcut.scope == 'global')
67
+ colisi�n = colisi�nAux2?(pointcut, self, fcode)
68
+ elsif (self.scope == 'global') and (pointcut.scope == 'local')
69
+ colisi�n = colisi�nAux2?(self, pointcut, fcode)
70
+ else #if (self.scope == 'global') and (pointcut.scope == 'global')
71
+ colisi�n = ( colisi�nAux2?(self, pointcut, fcode) or
72
+ colisi�nAux2?(pointcut, self, fcode) )
73
+ end #if
74
+ }
75
+ return colisi�n
76
+ end #colisi�n?
77
+
78
+ end #Pointcut
79
+
80
+ #Auxiliar AspectGen class that represents an Advice
81
+ class Advice
82
+ #Advice name (a String)
83
+ attr_accessor :name
84
+ #Name of the Pointcut associated with the Advice (a String)
85
+ attr_accessor :pointcut
86
+ #Advice value. String that will replace the text matched by the Pointcut value
87
+ attr_accessor :subText
88
+
89
+ # * 'name' = Advice name (a String)
90
+ # * 'pointcut' = Name of the Pointcut associated with the Advice (a String)
91
+ # * 'subtext' = Advice value. String that will replace the text matched by the Pointcut value
92
+ def constructor(name, pointcut, subText)
93
+
94
+ raise "Arguments of Advice constructor must be a String" if (!name.kind_of?(String)) or
95
+ (!pointcut.kind_of?(String)) or (!subText.kind_of?(String))
96
+ @name = name
97
+ @pointcut = pointcut
98
+ @subText = subText
99
+ end #constructor
100
+
101
+ def clone
102
+ result = Advice.new(@name.clone, @pointcut.clone, @subText.clone)
103
+ end #clone
104
+
105
+ end #Advice
106
+
107
+ #Auxiliar AspectGen class that represents a Generation
108
+ class Generation
109
+ #Generation name (a String)
110
+ attr_accessor :name
111
+ #Generation sterotype file (a String)
112
+ attr_accessor :fin
113
+ #Generation output file (a String)
114
+ attr_accessor :fout
115
+ #List of Advice names associated with the Generation (a String List)
116
+ attr_accessor :adviceList
117
+
118
+ # * 'name' = Generation name (a String)
119
+ # * 'fin' = Generation sterotype file (a String)
120
+ # * 'fout' = Generation output file (a String)
121
+ # * 'adviceList' = List of Advice names associated with the Generation (a String List)
122
+ def constructor(name, fin, fout, adviceList = [])
123
+ raise "First argument of Generation constructor must be a String" if !name.kind_of?(String)
124
+ raise "Fourth argument of Generation constructor must be a String List" if !adviceList.kind_of?(Array)
125
+ adviceList.each { |a|
126
+ raise "Fourth argument of Generation constructor must be a String List" if !a.kind_of?(String)
127
+ } #adviceList.each
128
+ @name = name
129
+ @fin = fin
130
+ @fout = fout
131
+ @adviceList = adviceList
132
+ end #constructor
133
+
134
+ def clone
135
+ result = Generation.new(@name, @fin, @fout, @adviceList.clone)
136
+ end #clone
137
+
138
+ end #Generation
139
+
140
+ class AspectGen
141
+
142
+ # Counter used by cloneSuffix
143
+ @@suffixes = 0
144
+
145
+ # Protected Binding object that describes the variable and method bindings at the point of constructor call
146
+ attr_accessor :args
147
+ # Protected hash table that stores the Pointcuts of 'self'
148
+ attr_accessor :pointcutHash
149
+ # Protected hash table that stores the Advices of 'self'
150
+ attr_accessor :adviceHash
151
+ # Protected hash table that stores the Generations of 'self'
152
+ attr_accessor :generationHash
153
+
154
+ #@pointcutHash = {}
155
+ @adviceHash = {}
156
+ @generationHash = {}
157
+
158
+ #Esto habr�a que verlo
159
+ protected :pointcutHash, :adviceHash, :generationHash
160
+
161
+ def clone
162
+ result = AspectGen.new(@args)
163
+ result.pointcutHash = @pointcutHash.clone
164
+ result.adviceHash = @adviceHash.clone
165
+ result.generationHash = @generationHash.clone
166
+ return result
167
+ end #clone
168
+
169
+ # + auxiliar method that produces a clone where all elements (Pointcuts, Advices and Generations) have been added
170
+ # a numerical suffix (@@suffixes is a private class attribute that will be incremented everytime method '+' is
171
+ # called).
172
+ # For example, if @suffixes value is 8, then
173
+ #
174
+ # pointcut('p1', /expReg/, 'global') -> pointcut('p1_8', /expReg/, 'global')
175
+ def cloneSuffix
176
+ result = self.clone
177
+ @generationHash.each { |k, g|
178
+ result.generationHash[k + '_' + @@suffixes.to_s] =
179
+ @generationHash[k]
180
+ result.generationHash[k + '_' + @@suffixes.to_s].name +=
181
+ '_' + @@suffixes.to_s
182
+ result.generationHash[k + '_' + @@suffixes.to_s].adviceList.collect! { |e|
183
+ e + '_' + @@suffixes.to_s
184
+ } #collect
185
+ result.generationHash.delete(k)
186
+ } #@generationHash.each
187
+ @adviceHash.each { |k, g|
188
+ result.adviceHash[k + '_' + @@suffixes.to_s] =
189
+ @adviceHash[k]
190
+ result.adviceHash[k + '_' + @@suffixes.to_s].name +=
191
+ '_' + @@suffixes.to_s
192
+ result.adviceHash[k + '_' + @@suffixes.to_s].pointcut +=
193
+ '_' + @@suffixes.to_s
194
+ result.adviceHash.delete(k)
195
+ } #@generationHash.each
196
+ @pointcutHash.each { |k, g|
197
+ result.pointcutHash[k + '_' + @@suffixes.to_s] =
198
+ @pointcutHash[k]
199
+ result.pointcutHash[k + '_' + @@suffixes.to_s].name +=
200
+ '_' + @@suffixes.to_s
201
+ result.pointcutHash.delete(k)
202
+ } #@generationHash.each
203
+ @@suffixes += 1
204
+ return result
205
+ end #cloneSuffix
206
+
207
+ # Adds a new Pointcut to 'self'
208
+ # * 'name' = Pointcut name (a String)
209
+ # * 'regExp' = Pointcut value (a Regexp)
210
+ # * 'scope' = Pointcut scope ('local' or 'global')
211
+ def pointcut(name, regExp, scope = 'local')
212
+ @pointcutHash = {} unless @pointcutHash
213
+ @pointcutHash[name] = Pointcut.new(name, regExp, scope)
214
+ end #pointcut
215
+
216
+ # Adds a new Advice to 'self'
217
+ # * 'name' = Advice name (a String)
218
+ # * 'pointcut' = Name of the Pointcut associated with the Advice (a String)
219
+ # * 'subtext' = Advice value. String that will replace the text matched by the Pointcut value
220
+ def advice(name, pointcut, subText)
221
+ raise "Pointcut referenced by AspectGen#advice doesn't exist" if pointcutHash[pointcut] == nil
222
+ @adviceHash = {} unless @adviceHash
223
+ @adviceHash[name] = Advice.new(name, pointcut, subText)
224
+ end #advice
225
+
226
+ # Adds a new Generation to 'self'
227
+ # * 'name' = Generation name (a String)
228
+ # * 'fin' = Generation sterotype file (a String)
229
+ # * 'fout' = Generation output file (a String)
230
+ # * 'adviceList' = List of Advice names associated with the Generation (a String List)
231
+ def generation(name, fin, fout, adviceList = [])
232
+ @generationHash = {} unless @generationHash
233
+
234
+ raise "Fourth argument of Generation constructor must be a String List" if !adviceList.kind_of?(Array)
235
+ adviceList.each { |a|
236
+ raise "Advice referenced by AspectGen#generation doesn't exist" if adviceHash[a] == nil
237
+ } #adviceList.each
238
+ adviceListAux = adviceList
239
+ adviceList.each { |a1|
240
+ adviceListAux -= [a1]
241
+ adviceListAux.each { |a2|
242
+ if @pointcutHash[@adviceHash[a1].pointcut].colisi�n?(@pointcutHash[@adviceHash[a2].pointcut], fin)
243
+ raise 'several pointcuts are colisi�ning'
244
+ end #if
245
+ } #adviceListAux.each
246
+ } #adviceList.each
247
+ generationHash.each { |k, g|
248
+ raise "There is another generation with the same output file" if (fout == g.fout) and (name != g.name)
249
+ } #generationHash.each
250
+ @generationHash[name] =
251
+ Generation.new(name, fin, fout, adviceList)
252
+ end #generation
253
+
254
+ # Executes all Generations of 'self'
255
+ def generate()
256
+ @generationHash.each_value { |g|
257
+ File.open(g.fin) {|fin|
258
+ stereotypeCode = fin.read
259
+ g.adviceList.each {|adviceKey|
260
+ if @pointcutHash[@adviceHash[adviceKey].pointcut].scope == 'global'
261
+ stereotypeCode.gsub!(@pointcutHash[@adviceHash[adviceKey].pointcut],
262
+ @adviceHash[adviceKey].subText)
263
+
264
+ else
265
+ stereotypeCode.sub!(@pointcutHash[@adviceHash[adviceKey].pointcut],
266
+ @adviceHash[adviceKey].subText)
267
+ end #if
268
+ } #g.adviceList.each
269
+ File.open(g.fout, "w+") {|fout|
270
+ fout.write(stereotypeCode)
271
+ } #File.open(g.fout, "w+")
272
+ } #File.open(g.fin)
273
+ } #@generationHash.each
274
+ end #generate
275
+
276
+ # Combines two AspectGen objects ('self' and 'aspectGen'). It can raise exceptions when:
277
+ # * Several Generations have the same output file but different stereotype files.
278
+ # * Several Generations have Pointcuts wich overlap ("colisi�n")
279
+ def +(aspectGen)
280
+ raise "Argument of AspectGen#+ must be a AspectGen" if !aspectGen.kind_of?(AspectGen)
281
+ a1 = self.cloneSuffix
282
+ a2 = aspectGen.cloneSuffix
283
+ a1.generationHash.each { |k1, g1|
284
+ a2.generationHash.each { |k2, g2|
285
+ if g1.fout == g2.fout
286
+ File.open(g1.fin) {|fin1|
287
+ stereotypeCode1 = fin1.read
288
+ File.open(g2.fin) {|fin2|
289
+ stereotypeCode2 = fin2.read
290
+ if stereotypeCode1 != stereotypeCode2
291
+ raise "Two generations with the same 'generation file' but different 'stereotype files'"
292
+ else
293
+ g1.adviceList.each {|ad1|
294
+ g2.adviceList.each {|ad2|
295
+ if a1.pointcutHash[a1.adviceHash[ad1].pointcut].colisi�n?(
296
+ a2.pointcutHash[a2.adviceHash[ad2].pointcut], g1.fin)
297
+ raise 'several pointcuts are colisi�ning'
298
+ end #if
299
+ } #g2.adviceList
300
+ } #g1.adviceList
301
+ g1.adviceList += g2.adviceList
302
+ a2.generationHash.delete(k2)
303
+ end #if
304
+ } #File.open(g2.fin)
305
+ } #File.open(g1.fin)
306
+ end #if
307
+ } #a2.generationHash.each
308
+ } #a1.generationHash.each
309
+ a1.generationHash.update(a2.generationHash)
310
+ a1.adviceHash.update(a2.adviceHash)
311
+ a1.pointcutHash.update(a2.pointcutHash)
312
+ return a1
313
+ end #+
314
+
315
+ def AspectGen.init(*ids)
316
+ # Falta gestion de errores
317
+ for id in ids
318
+ id_value = eval(id.id2name, @args)
319
+ eval "@#{id.id2name} = id_value"
320
+ end #for
321
+ yield if block_given?
322
+ end #interface
323
+
324
+ end #AspectGen
325
+
326
+
327
+
328
+
@@ -0,0 +1,328 @@
1
+ # Author:: Ruben Heradio Gil (mailto:rheradio@lsi.uned.es)
2
+
3
+ #Auxiliar AspectGen class that represents a Pointcut
4
+ class Pointcut < Regexp
5
+ #Pointcut name (a String)
6
+ attr_accessor :name
7
+ #Pointcut value (a Regexp)
8
+ attr_accessor :regExp
9
+ #Pointcut scope ('local' or 'global')
10
+ attr_accessor :scope
11
+
12
+ # * 'name' = Pointcut name (a String)
13
+ # * 'regExp' = Pointcut value (a Regexp)
14
+ # * 'scope' = Pointcut scope ('local' or 'global')
15
+ def constructor(name, regExp, scope='local')
16
+ raise "First argument of Pointcut constructor must be a String" if !name.kind_of?(String)
17
+ raise "Second argument of Pointcut constructor must be a Regular Expression" if !regExp.kind_of?(Regexp)
18
+ raise "Pointcut scope must be 'local' or 'global'" if (scope != 'local') and
19
+ (scope != 'global')
20
+ super(regExp)
21
+ @name = name
22
+ @regExp = regExp
23
+ @scope = scope
24
+ end #constructor
25
+
26
+ def clone
27
+ result = Pointcut.new(@name.clone, @regExp.clone, @scope.clone)
28
+ end #clone
29
+
30
+ #Determine if two Pointcuts ('self' and 'pointcut') applied over the same input file ('fin') go crash
31
+ def crash?(pointcut, fin)
32
+
33
+ raise "First argument of Pointcut#crash? must be a Pointcut" if !pointcut.kind_of?(Pointcut)
34
+ # crash? inner auxiliar method that determines if two local Pointcuts ('pointcut1' and 'pointcut2') applied over the String tr' go crash
35
+ def crashAux1?(pointcut1, pointcut2, str)
36
+ position1 = str =~ pointcut1
37
+ match1 = $&
38
+ position2 = str =~ pointcut2
39
+ match2 = $&
40
+ return false if (position1 == nil) or (position2 == nil)
41
+ if (position1 <= position2)
42
+ return true if (position1 + match1.length - 1) >= position2
43
+ else
44
+ return true if (position2 + match2.length - 1) >= position1
45
+ end #if
46
+ return false
47
+ end #crashAux1?
48
+
49
+ # crash? inner auxiliar method that determines if a global Pointcut ('globalPointcut') and a local
50
+ # Pointcut ('localPointcut') applied over the String tr' go crash
51
+ def crashAux2?(globalPointcut, localPointcut, str)
52
+ crash = false
53
+ while (str.index(globalPointcut) != nil) and (crash == false)
54
+ crash = crashAux1?(globalPointcut, localPointcut, str)
55
+ str =~ globalPointcut
56
+ str = $'
57
+ end #while
58
+ return crash
59
+ end
60
+
61
+ crash = false
62
+ File.open(fin) { |f|
63
+ fcode = f.read
64
+ if (self.scope == 'local') and (pointcut.scope == 'local')
65
+ crash = crashAux1?(self, pointcut, fcode)
66
+ elsif (self.scope == 'local') and (pointcut.scope == 'global')
67
+ crash = crashAux2?(pointcut, self, fcode)
68
+ elsif (self.scope == 'global') and (pointcut.scope == 'local')
69
+ crash = crashAux2?(self, pointcut, fcode)
70
+ else #if (self.scope == 'global') and (pointcut.scope == 'global')
71
+ crash = ( crashAux2?(self, pointcut, fcode) or
72
+ crashAux2?(pointcut, self, fcode) )
73
+ end #if
74
+ }
75
+ return crash
76
+ end #crash?
77
+
78
+ end #Pointcut
79
+
80
+ #Auxiliar AspectGen class that represents an Advice
81
+ class Advice
82
+ #Advice name (a String)
83
+ attr_accessor :name
84
+ #Name of the Pointcut associated with the Advice (a String)
85
+ attr_accessor :pointcut
86
+ #Advice value. String that will replace the text matched by the Pointcut value
87
+ attr_accessor :subText
88
+
89
+ # * 'name' = Advice name (a String)
90
+ # * 'pointcut' = Name of the Pointcut associated with the Advice (a String)
91
+ # * 'subtext' = Advice value. String that will replace the text matched by the Pointcut value
92
+ def constructor(name, pointcut, subText)
93
+
94
+ raise "Arguments of Advice constructor must be a String" if (!name.kind_of?(String)) or
95
+ (!pointcut.kind_of?(String)) or (!subText.kind_of?(String))
96
+ @name = name
97
+ @pointcut = pointcut
98
+ @subText = subText
99
+ end #constructor
100
+
101
+ def clone
102
+ result = Advice.new(@name.clone, @pointcut.clone, @subText.clone)
103
+ end #clone
104
+
105
+ end #Advice
106
+
107
+ #Auxiliar AspectGen class that represents a Generation
108
+ class Generation
109
+ #Generation name (a String)
110
+ attr_accessor :name
111
+ #Generation sterotype file (a String)
112
+ attr_accessor :fin
113
+ #Generation output file (a String)
114
+ attr_accessor :fout
115
+ #List of Advice names associated with the Generation (a String List)
116
+ attr_accessor :adviceList
117
+
118
+ # * 'name' = Generation name (a String)
119
+ # * 'fin' = Generation sterotype file (a String)
120
+ # * 'fout' = Generation output file (a String)
121
+ # * 'adviceList' = List of Advice names associated with the Generation (a String List)
122
+ def constructor(name, fin, fout, adviceList = [])
123
+ raise "First argument of Generation constructor must be a String" if !name.kind_of?(String)
124
+ raise "Fourth argument of Generation constructor must be a String List" if !adviceList.kind_of?(Array)
125
+ adviceList.each { |a|
126
+ raise "Fourth argument of Generation constructor must be a String List" if !a.kind_of?(String)
127
+ } #adviceList.each
128
+ @name = name
129
+ @fin = fin
130
+ @fout = fout
131
+ @adviceList = adviceList
132
+ end #constructor
133
+
134
+ def clone
135
+ result = Generation.new(@name, @fin, @fout, @adviceList.clone)
136
+ end #clone
137
+
138
+ end #Generation
139
+
140
+ class AspectGen
141
+
142
+ # Counter used by cloneSuffix
143
+ @@suffixes = 0
144
+
145
+ # Protected Binding object that describes the variable and method bindings at the point of constructor call
146
+ attr_accessor :args
147
+ # Protected hash table that stores the Pointcuts of 'self'
148
+ attr_accessor :pointcutHash
149
+ # Protected hash table that stores the Advices of 'self'
150
+ attr_accessor :adviceHash
151
+ # Protected hash table that stores the Generations of 'self'
152
+ attr_accessor :generationHash
153
+
154
+ #@pointcutHash = {}
155
+ @adviceHash = {}
156
+ @generationHash = {}
157
+
158
+ #Esto habr�a que verlo
159
+ protected :pointcutHash, :adviceHash, :generationHash
160
+
161
+ def clone
162
+ result = AspectGen.new(@args)
163
+ result.pointcutHash = @pointcutHash.clone
164
+ result.adviceHash = @adviceHash.clone
165
+ result.generationHash = @generationHash.clone
166
+ return result
167
+ end #clone
168
+
169
+ # + auxiliar method that produces a clone where all elements (Pointcuts, Advices and Generations) have been added
170
+ # a numerical suffix (@@suffixes is a private class attribute that will be incremented everytime method '+' is
171
+ # called).
172
+ # For example, if @suffixes value is 8, then
173
+ #
174
+ # pointcut('p1', /expReg/, 'global') -> pointcut('p1_8', /expReg/, 'global')
175
+ def cloneSuffix
176
+ result = self.clone
177
+ @generationHash.each { |k, g|
178
+ result.generationHash[k + '_' + @@suffixes.to_s] =
179
+ @generationHash[k]
180
+ result.generationHash[k + '_' + @@suffixes.to_s].name +=
181
+ '_' + @@suffixes.to_s
182
+ result.generationHash[k + '_' + @@suffixes.to_s].adviceList.collect! { |e|
183
+ e + '_' + @@suffixes.to_s
184
+ } #collect
185
+ result.generationHash.delete(k)
186
+ } #@generationHash.each
187
+ @adviceHash.each { |k, g|
188
+ result.adviceHash[k + '_' + @@suffixes.to_s] =
189
+ @adviceHash[k]
190
+ result.adviceHash[k + '_' + @@suffixes.to_s].name +=
191
+ '_' + @@suffixes.to_s
192
+ result.adviceHash[k + '_' + @@suffixes.to_s].pointcut +=
193
+ '_' + @@suffixes.to_s
194
+ result.adviceHash.delete(k)
195
+ } #@generationHash.each
196
+ @pointcutHash.each { |k, g|
197
+ result.pointcutHash[k + '_' + @@suffixes.to_s] =
198
+ @pointcutHash[k]
199
+ result.pointcutHash[k + '_' + @@suffixes.to_s].name +=
200
+ '_' + @@suffixes.to_s
201
+ result.pointcutHash.delete(k)
202
+ } #@generationHash.each
203
+ @@suffixes += 1
204
+ return result
205
+ end #cloneSuffix
206
+
207
+ # Adds a new Pointcut to 'self'
208
+ # * 'name' = Pointcut name (a String)
209
+ # * 'regExp' = Pointcut value (a Regexp)
210
+ # * 'scope' = Pointcut scope ('local' or 'global')
211
+ def pointcut(name, regExp, scope = 'local')
212
+ @pointcutHash = {} unless @pointcutHash
213
+ @pointcutHash[name] = Pointcut.new(name, regExp, scope)
214
+ end #pointcut
215
+
216
+ # Adds a new Advice to 'self'
217
+ # * 'name' = Advice name (a String)
218
+ # * 'pointcut' = Name of the Pointcut associated with the Advice (a String)
219
+ # * 'subtext' = Advice value. String that will replace the text matched by the Pointcut value
220
+ def advice(name, pointcut, subText)
221
+ raise "Pointcut referenced by AspectGen#advice doesn't exist" if pointcutHash[pointcut] == nil
222
+ @adviceHash = {} unless @adviceHash
223
+ @adviceHash[name] = Advice.new(name, pointcut, subText)
224
+ end #advice
225
+
226
+ # Adds a new Generation to 'self'
227
+ # * 'name' = Generation name (a String)
228
+ # * 'fin' = Generation sterotype file (a String)
229
+ # * 'fout' = Generation output file (a String)
230
+ # * 'adviceList' = List of Advice names associated with the Generation (a String List)
231
+ def generation(name, fin, fout, adviceList = [])
232
+ @generationHash = {} unless @generationHash
233
+
234
+ raise "Fourth argument of Generation constructor must be a String List" if !adviceList.kind_of?(Array)
235
+ adviceList.each { |a|
236
+ raise "Advice referenced by AspectGen#generation doesn't exist" if adviceHash[a] == nil
237
+ } #adviceList.each
238
+ adviceListAux = adviceList
239
+ adviceList.each { |a1|
240
+ adviceListAux -= [a1]
241
+ adviceListAux.each { |a2|
242
+ if @pointcutHash[@adviceHash[a1].pointcut].crash?(@pointcutHash[@adviceHash[a2].pointcut], fin)
243
+ raise 'several pointcuts are crashing'
244
+ end #if
245
+ } #adviceListAux.each
246
+ } #adviceList.each
247
+ generationHash.each { |k, g|
248
+ raise "There is another generation with the same output file" if (fout == g.fout) and (name != g.name)
249
+ } #generationHash.each
250
+ @generationHash[name] =
251
+ Generation.new(name, fin, fout, adviceList)
252
+ end #generation
253
+
254
+ # Executes all Generations of 'self'
255
+ def generate()
256
+ @generationHash.each_value { |g|
257
+ File.open(g.fin) {|fin|
258
+ stereotypeCode = fin.read
259
+ g.adviceList.each {|adviceKey|
260
+ if @pointcutHash[@adviceHash[adviceKey].pointcut].scope == 'global'
261
+ stereotypeCode.gsub!(@pointcutHash[@adviceHash[adviceKey].pointcut],
262
+ @adviceHash[adviceKey].subText)
263
+
264
+ else
265
+ stereotypeCode.sub!(@pointcutHash[@adviceHash[adviceKey].pointcut],
266
+ @adviceHash[adviceKey].subText)
267
+ end #if
268
+ } #g.adviceList.each
269
+ File.open(g.fout, "w+") {|fout|
270
+ fout.write(stereotypeCode)
271
+ } #File.open(g.fout, "w+")
272
+ } #File.open(g.fin)
273
+ } #@generationHash.each
274
+ end #generate
275
+
276
+ # Combines two AspectGen objects ('self' and 'aspectGen'). It can raise exceptions when:
277
+ # * Several Generations have the same output file but different stereotype files.
278
+ # * Several Generations have Pointcuts wich overlap ("crash")
279
+ def +(aspectGen)
280
+ raise "Argument of AspectGen#+ must be a AspectGen" if !aspectGen.kind_of?(AspectGen)
281
+ a1 = self.cloneSuffix
282
+ a2 = aspectGen.cloneSuffix
283
+ a1.generationHash.each { |k1, g1|
284
+ a2.generationHash.each { |k2, g2|
285
+ if g1.fout == g2.fout
286
+ File.open(g1.fin) {|fin1|
287
+ stereotypeCode1 = fin1.read
288
+ File.open(g2.fin) {|fin2|
289
+ stereotypeCode2 = fin2.read
290
+ if stereotypeCode1 != stereotypeCode2
291
+ raise "Two generations with the same 'generation file' but different 'stereotype files'"
292
+ else
293
+ g1.adviceList.each {|ad1|
294
+ g2.adviceList.each {|ad2|
295
+ if a1.pointcutHash[a1.adviceHash[ad1].pointcut].crash?(
296
+ a2.pointcutHash[a2.adviceHash[ad2].pointcut], g1.fin)
297
+ raise 'several pointcuts are crashing'
298
+ end #if
299
+ } #g2.adviceList
300
+ } #g1.adviceList
301
+ g1.adviceList += g2.adviceList
302
+ a2.generationHash.delete(k2)
303
+ end #if
304
+ } #File.open(g2.fin)
305
+ } #File.open(g1.fin)
306
+ end #if
307
+ } #a2.generationHash.each
308
+ } #a1.generationHash.each
309
+ a1.generationHash.update(a2.generationHash)
310
+ a1.adviceHash.update(a2.adviceHash)
311
+ a1.pointcutHash.update(a2.pointcutHash)
312
+ return a1
313
+ end #+
314
+
315
+ def AspectGen.init(*ids)
316
+ # Falta gestion de errores
317
+ for id in ids
318
+ id_value = eval(id.id2name, @args)
319
+ eval "@#{id.id2name} = id_value"
320
+ end #for
321
+ yield if block_given?
322
+ end #interface
323
+
324
+ end #AspectGen
325
+
326
+
327
+
328
+