Skip to content

Commit d39c2c3

Browse files
committed
Add macro() Fix bind and function.
1 parent bec6763 commit d39c2c3

File tree

6 files changed

+218
-12
lines changed

6 files changed

+218
-12
lines changed

README.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ put_map("<mapName>",
192192

193193
##### `put_var`
194194

195-
Defines a single internal variable that can be referenced with `$[<variableName>]`.
195+
Defines a single global variable that can be referenced with `$[<variableName>]`.
196196

197197
```perl
198198
put_var("<variableName>", "<variableValue>")
199199
```
200200

201201
##### `put_vars`
202202

203-
Defines multiple internal variables that can be referenced with `$[<variableName>]`.
203+
Defines multiple global variables that can be referenced with `$[<variableName>]`.
204204

205205
```perl
206206
put_vars(
@@ -266,6 +266,25 @@ hash("foo")
266266
# ["name", "value"] => {"name":"value"}
267267
```
268268

269+
##### `macro`
270+
271+
Calls a named macro, i.e. a list of statements that have been previously defined with the [`do macro`](#do-macro) bind.
272+
273+
Parameters:
274+
275+
- `name` (required): Unique name of the macro.
276+
277+
Options:
278+
279+
- All options are made available as "dynamic" local variables.
280+
281+
```perl
282+
do macro("<macroName>"[, <staticLocalVariables>...])
283+
...
284+
end
285+
macro("<macroName>"[, <dynamicLocalVariables>...])
286+
```
287+
269288
##### `move_field`
270289

271290
Moves (or appends to) a field from an existing field. Can be used to rename a field.
@@ -613,6 +632,25 @@ do list(path: "<sourceField>", "var": "<variableName>")
613632
end
614633
```
615634

635+
#### `do macro`
636+
637+
Defines a named macro, i.e. a list of statements that can be executed later with the [`macro`](#macro) function.
638+
639+
Parameters:
640+
641+
- `name` (required): Unique name of the macro.
642+
643+
Options:
644+
645+
- All options are made available as "static" local variables.
646+
647+
```perl
648+
do macro("<macroName>"[, <staticLocalVariables>...])
649+
...
650+
end
651+
macro("<macroName>"[, <dynamicLocalVariables>...])
652+
```
653+
616654
#### `do once`
617655

618656
Executes the statements only once (when the bind is first encountered), not repeatedly for each record.

metafix/src/main/java/org/metafacture/metafix/FixBind.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,16 @@ public void execute(final Metafix metafix, final Record record, final List<Strin
6060
}
6161
},
6262

63+
macro {
64+
@Override
65+
public void execute(final Metafix metafix, final Record record, final List<String> params, final Map<String, String> options, final RecordTransformer recordTransformer) {
66+
recordTransformer.addVars(options);
67+
metafix.putMacro(params.get(0), recordTransformer);
68+
}
69+
},
70+
6371
once {
64-
private Map<Metafix, Set<String>> executed = new HashMap<>();
72+
private final Map<Metafix, Set<String>> executed = new HashMap<>();
6573

6674
@Override
6775
public void execute(final Metafix metafix, final Record record, final List<String> params, final Map<String, String> options, final RecordTransformer recordTransformer) {

metafix/src/main/java/org/metafacture/metafix/FixMethod.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ public void apply(final Metafix metafix, final Record record, final List<String>
153153
})));
154154
}
155155
},
156+
macro {
157+
@Override
158+
public void apply(final Metafix metafix, final Record record, final List<String> params, final Map<String, String> options) {
159+
final RecordTransformer recordTransformer = metafix.getMacro(params.get(0));
160+
if (recordTransformer != null) {
161+
recordTransformer.transform(record, options);
162+
}
163+
else {
164+
// TODO?: Metamorph throws MorphBuildException("Macro '" + macroName + "' undefined!")
165+
}
166+
}
167+
},
156168
move_field {
157169
@Override
158170
public void apply(final Metafix metafix, final Record record, final List<String> params, final Map<String, String> options) {

metafix/src/main/java/org/metafacture/metafix/Metafix.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps {
7272
private final Deque<Integer> entityCountStack = new LinkedList<>();
7373
private final List<Closeable> resources = new ArrayList<>();
7474
private final List<Expression> expressions = new ArrayList<>();
75-
private final Map<String, RecordTransformer> fixCache = new HashMap<>();
7675
private final Map<String, Map<String, String>> maps = new HashMap<>();
76+
private final Map<String, RecordTransformer> fixCache = new HashMap<>();
77+
private final Map<String, RecordTransformer> macros = new HashMap<>();
7778
private final Map<String, String> vars = new HashMap<>();
7879
private final RecordTransformer recordTransformer;
7980
private final StreamFlattener flattener = new StreamFlattener();
@@ -163,6 +164,14 @@ private RecordTransformer getRecordTransformer(final Reader fixDef) {
163164
return new RecordTransformer(this, FixStandaloneSetup.parseFix(fixDef));
164165
}
165166

167+
public void putMacro(final String name, final RecordTransformer macro) {
168+
macros.put(name, macro);
169+
}
170+
171+
public RecordTransformer getMacro(final String name) {
172+
return macros.get(name);
173+
}
174+
166175
public List<Expression> getExpressions() {
167176
return expressions;
168177
}

metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.slf4j.LoggerFactory;
3939

4040
import java.util.ArrayList;
41+
import java.util.HashMap;
4142
import java.util.LinkedHashMap;
4243
import java.util.LinkedList;
4344
import java.util.List;
@@ -47,6 +48,8 @@
4748
import java.util.function.Supplier;
4849
import java.util.stream.Collectors;
4950

51+
// TODO: Utilize org.metafacture.commons.types.ScopedHashMap for vars instead?
52+
5053
/**
5154
* Transform a record using a {@link Fix}.
5255
*
@@ -58,7 +61,7 @@ public class RecordTransformer { // checkstyle-disable-line ClassFanOutComplexit
5861
private static final Logger LOG = LoggerFactory.getLogger(RecordTransformer.class);
5962

6063
private final List<Consumer<Record>> consumers = new LinkedList<>();
61-
private final Map<String, String> vars;
64+
private final List<Map<String, String>> vars = new ArrayList<>();
6265
private final Metafix metafix;
6366

6467
private Supplier<String> currentMessageSupplier;
@@ -69,7 +72,7 @@ public class RecordTransformer { // checkstyle-disable-line ClassFanOutComplexit
6972

7073
private RecordTransformer(final Metafix metafix, final List<Expression> expressions) {
7174
this.metafix = metafix;
72-
vars = metafix.getVars();
75+
addVars(metafix.getVars());
7376

7477
expressions.forEach(e -> {
7578
final Params params = new Params(e.getParams(), vars);
@@ -93,6 +96,22 @@ else if (e instanceof MethodCall) {
9396
});
9497
}
9598

99+
public void addVars(final Map<String, String> additionalVars) {
100+
vars.add(additionalVars);
101+
}
102+
103+
public void transform(final Record record, final Map<String, String> additionalVars) {
104+
final int index = vars.size();
105+
addVars(additionalVars);
106+
107+
try {
108+
transform(record);
109+
}
110+
finally {
111+
vars.remove(index);
112+
}
113+
}
114+
96115
public void transform(final Record record) {
97116
consumers.forEach(consumer -> {
98117
final FixExecutionException exception = tryRun(() -> consumer.accept(record));
@@ -246,17 +265,23 @@ protected String resolveVars(final String value, final Map<String, String> vars)
246265
return value == null ? null : StringUtil.format(value, Metafix.VAR_START, Metafix.VAR_END, false, vars);
247266
}
248267

268+
protected Map<String, String> mergeVars(final List<Map<String, String>> vars) {
269+
final Map<String, String> mergedVars = new HashMap<>();
270+
vars.forEach(mergedVars::putAll);
271+
return mergedVars;
272+
}
273+
249274
protected abstract T resolve();
250275

251276
}
252277

253278
private static class Params extends AbstractResolvable<List<String>> {
254279

255280
private final List<String> list;
256-
private final Map<String, String> vars;
281+
private final List<Map<String, String>> vars;
257282
private final boolean resolve;
258283

259-
private Params(final List<String> list, final Map<String, String> vars) {
284+
private Params(final List<String> list, final List<Map<String, String>> vars) {
260285
this.list = list;
261286
this.vars = vars;
262287

@@ -267,9 +292,10 @@ private Params(final List<String> list, final Map<String, String> vars) {
267292
protected List<String> resolve() {
268293
if (resolve) {
269294
final List<String> resolvedList = new ArrayList<>(list.size());
295+
final Map<String, String> mergedVars = mergeVars(vars);
270296

271297
for (final String entry : list) {
272-
resolvedList.add(resolveVars(entry, vars));
298+
resolvedList.add(resolveVars(entry, mergedVars));
273299
}
274300

275301
return resolvedList;
@@ -284,10 +310,10 @@ protected List<String> resolve() {
284310
private static class Options extends AbstractResolvable<Map<String, String>> {
285311

286312
private final Map<String, String> map = new LinkedHashMap<>();
287-
private final Map<String, String> vars;
313+
private final List<Map<String, String>> vars;
288314
private final boolean resolve;
289315

290-
private Options(final org.metafacture.metafix.fix.Options options, final Map<String, String> vars) {
316+
private Options(final org.metafacture.metafix.fix.Options options, final List<Map<String, String>> vars) {
291317
this.vars = vars;
292318

293319
boolean resolveTemp = false;
@@ -315,9 +341,10 @@ private Options(final org.metafacture.metafix.fix.Options options, final Map<Str
315341
protected Map<String, String> resolve() {
316342
if (resolve) {
317343
final Map<String, String> resolvedMap = new LinkedHashMap<>(map.size());
344+
final Map<String, String> mergedVars = mergeVars(vars);
318345

319346
for (final Map.Entry<String, String> entry : map.entrySet()) {
320-
resolvedMap.put(resolveVars(entry.getKey(), vars), resolveVars(entry.getValue(), vars));
347+
resolvedMap.put(resolveVars(entry.getKey(), mergedVars), resolveVars(entry.getValue(), mergedVars));
321348
}
322349

323350
return resolvedMap;

metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,118 @@ public void arrayFromHash() {
19891989
});
19901990
}
19911991

1992+
@Test
1993+
public void shouldCallMacro() {
1994+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
1995+
"do macro('test')",
1996+
" add_field('test', '42')",
1997+
"end",
1998+
"macro('test')",
1999+
"macro('test')"
2000+
),
2001+
i -> {
2002+
i.startRecord("1");
2003+
i.endRecord();
2004+
},
2005+
(o, f) -> {
2006+
o.get().startRecord("1");
2007+
f.apply(2).literal("test", "42");
2008+
o.get().endRecord();
2009+
}
2010+
);
2011+
}
2012+
2013+
@Test
2014+
public void shouldNotCallUnknownMacro() {
2015+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2016+
"macro('test')",
2017+
"macro('test')"
2018+
),
2019+
i -> {
2020+
i.startRecord("1");
2021+
i.endRecord();
2022+
},
2023+
o -> {
2024+
o.get().startRecord("1");
2025+
o.get().endRecord();
2026+
}
2027+
);
2028+
}
2029+
2030+
@Test
2031+
public void shouldCallMacroWithVariables() {
2032+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2033+
"put_vars(a: '1', b: '2')", // global variables
2034+
"do macro('test', b: '22', c: '33')", // "static" local variables
2035+
" add_field('test', '$[a]-$[b]-$[c]-$[d]')",
2036+
"end",
2037+
"macro('test', c: '333', d: '444')", // "dynamic" local variables
2038+
"macro('test', b: '555', d: '666')",
2039+
"add_field('vars', '$[a]-$[b]')"
2040+
),
2041+
i -> {
2042+
i.startRecord("1");
2043+
i.endRecord();
2044+
},
2045+
o -> {
2046+
o.get().startRecord("1");
2047+
o.get().literal("test", "1-22-333-444");
2048+
o.get().literal("test", "1-555-33-666");
2049+
o.get().literal("vars", "1-2");
2050+
o.get().endRecord();
2051+
}
2052+
);
2053+
}
2054+
2055+
@Test
2056+
public void shouldNotLeakVariablesFromMacro() {
2057+
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "Variable 'c' was not assigned!\nAssigned variables:\n{a=1, b=2}", () ->
2058+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2059+
"put_vars(a: '1', b: '2')", // global variables
2060+
"do macro('test', b: '22', c: '33')", // "static" local variables
2061+
"end",
2062+
"macro('test', c: '333', d: '444')", // "dynamic" local variables
2063+
"macro('test', b: '555', d: '666')",
2064+
"add_field('test', '$[a]-$[b]-$[c]-$[d]')"
2065+
),
2066+
i -> {
2067+
i.startRecord("1");
2068+
i.endRecord();
2069+
},
2070+
o -> {
2071+
}
2072+
)
2073+
);
2074+
}
2075+
2076+
@Test
2077+
public void shouldCallNestedMacro() {
2078+
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
2079+
"do macro('test1', c: '23')",
2080+
" add_field('test$[a]', '42')",
2081+
" macro('test2', b: '$[b]', c: '$[c]')",
2082+
"end",
2083+
"do macro('test2')",
2084+
" add_field('test$[b]', '$[c]')",
2085+
"end",
2086+
"macro('test1', a: '1', b: '2')",
2087+
"macro('test1', a: '3', b: '4')"
2088+
),
2089+
i -> {
2090+
i.startRecord("1");
2091+
i.endRecord();
2092+
},
2093+
o -> {
2094+
o.get().startRecord("1");
2095+
o.get().literal("test1", "42");
2096+
o.get().literal("test2", "23");
2097+
o.get().literal("test3", "42");
2098+
o.get().literal("test4", "23");
2099+
o.get().endRecord();
2100+
}
2101+
);
2102+
}
2103+
19922104
@Test
19932105
public void reject() {
19942106
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(

0 commit comments

Comments
 (0)