Skip to content
This repository has been archived by the owner on Jan 27, 2025. It is now read-only.

Don't restrict bind scope to the bound var #83

Merged
merged 4 commits into from
Dec 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
run: ./gradlew build
- name: Install language server
run: ./gradlew installServer
- name: Change directory
run: cd metafix-vsc/
- name: Install fix extension
working-directory: metafix-vsc/
run: npm install
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,33 @@ else if (sub instanceof Unless) {
private void processBind(final Do theDo, final EList<String> params) {
if (theDo.getName().equals("list")) { // TODO impl multiple binds via FixBind enum
final Map<String, String> options = options(theDo.getOptions());
final Record fullRecord = record.shallowClone();

record.findList(options.get("path"), a -> a.forEach(value -> {
// for each value, bind the current record/scope/context to the given var name:
record = new Record();
record.put(options.get("var"), value);

processSubexpressions(theDo.getElements());
record.remove(options.get("var"));

// and remember the things we added while bound (this probably needs some tweaking):
fullRecord.addAll(record);
}));

record = fullRecord;
record.findList(options.get("path"), a -> {
for (int i = 0; i < a.size(); ++i) {
final Value value = a.get(i);
final String var = options.get("var");
// with var -> keep full record in scope, add the var:
if (var != null) {
record.put(var, value);
processSubexpressions(theDo.getElements());
record.remove(var);
}
// w/o var -> use the currently bound value as the record:
else {
if (value.isHash()) {
final Record fullRecord = record;
record = new Record();
record.addAll(value.asHash());
processSubexpressions(theDo.getElements());
a.set(i, new Value(record));
record = fullRecord;
}
else {
// TODO: bind to arrays (if that makes sense) and strings (access with '.')
throw new IllegalStateException("expected hash, got " + value);
}
}
}
});
}
else {
LOG.warn("Unprocessed bind: {}", theDo);
Expand Down
5 changes: 5 additions & 0 deletions metafix/src/main/java/org/metafacture/metafix/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,11 @@ private void insert(final InsertMode mode, final String[] fields, final String n
break;
}
}

/*package-private*/ void set(final int index, final Value value) {
list.set(index, value);
}

}

/**
Expand Down
100 changes: 99 additions & 1 deletion metafix/src/test/java/org/metafacture/metafix/MetafixBindTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,104 @@ public void doList() {
});
}

@Test
public void doListFullRecordInScope() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
"do list('path': 'name', 'var': 'n')",
" if any_equal('type','book')",
" paste('title','~Book:','n')",
" else",
" paste('title','~Journal:','n')",
" end",
"end",
"retain('title')"),
i -> {
i.startRecord("1");
i.literal("type", "book");
i.literal("name", "A book");
i.endRecord();
i.startRecord("2");
i.literal("type", "journal");
i.literal("name", "A journal");
i.endRecord();
}, o -> {
o.get().startRecord("1");
o.get().literal("title", "Book: A book");
o.get().endRecord();
o.get().startRecord("2");
o.get().literal("title", "Journal: A journal");
o.get().endRecord();
});
}

@Test
public void bindingScopeWithVar() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
"do list('path':'foo','var':'loop')",
" copy_field('test','loop.baz')",
" copy_field('loop.bar','loop.qux')",
"end"),
i -> {
i.startRecord("1");
i.startEntity("foo");
i.literal("bar", "1");
i.endEntity();
i.startEntity("foo");
i.literal("bar", "2");
i.endEntity();
i.literal("test", "42");
i.endRecord();
}, (o, f) -> {
o.get().startRecord("1");
o.get().startEntity("foo");
o.get().startEntity("1");
o.get().literal("bar", "1");
o.get().literal("baz", "42");
o.get().literal("qux", "1");
f.apply(1).endEntity();
o.get().startEntity("2");
o.get().literal("bar", "2");
o.get().literal("baz", "42");
o.get().literal("qux", "2");
f.apply(2).endEntity();
o.get().literal("test", "42");
o.get().endRecord();
});
}

@Test
public void bindingScopeWithoutVar() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
"do list('path':'foo')",
" copy_field('test','baz')",
" copy_field('bar','qux')",
"end"),
i -> {
i.startRecord("1");
i.startEntity("foo");
i.literal("bar", "1");
i.endEntity();
i.startEntity("foo");
i.literal("bar", "2");
i.endEntity();
i.literal("test", "42");
i.endRecord();
}, (o, f) -> {
o.get().startRecord("1");
o.get().startEntity("foo");
o.get().startEntity("1");
o.get().literal("bar", "1");
o.get().literal("qux", "1");
f.apply(1).endEntity();
o.get().startEntity("2");
o.get().literal("bar", "2");
o.get().literal("qux", "2");
f.apply(2).endEntity();
o.get().literal("test", "42");
o.get().endRecord();
});
}

@Test
public void doListPathWithDots() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
Expand Down Expand Up @@ -99,8 +197,8 @@ public void doListPathWithDots() {
@Test
public void doListWithAppendAndLast() {
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
"set_array('author[]')",
"do list('path': 'creator', 'var': 'c')",
" set_array('author[]')",
" copy_field('c.name', 'author[].$append.name')",
" add_field('author[].$last.type', 'Default')",
"end",
Expand Down