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

Commit

Permalink
Move static record/hash methods to Value/Hash class. (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
blackwinter committed Nov 16, 2021
1 parent 7a8b800 commit 73a0563
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 232 deletions.
216 changes: 44 additions & 172 deletions metafix/src/main/java/org/metafacture/metafix/FixMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand All @@ -32,16 +31,18 @@ enum FixMethod {

set_field {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
record.remove(params.get(0));
insert(InsertMode.REPLACE, record, split(params.get(0)), params.get(1));
final String field = params.get(0);

record.remove(field);
record.replace(field, params.get(1));
}
},
set_array {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
final String field = params.get(0);
final List<String> toAdd = params.subList(1, params.size());
if (field.endsWith(DOT_APPEND)) {
Metafix.addAll(record, field.replace(DOT_APPEND, EMPTY), toAdd);
record.addAll(field.replace(DOT_APPEND, EMPTY), toAdd);
}
else {
record.put(field, Value.newArray(a -> toAdd.forEach(s -> a.add(new Value(s)))));
Expand All @@ -65,63 +66,71 @@ public void apply(final Record record, final List<String> params, final Map<Stri
},
array { // array-from-hash
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
final String fieldName = params.get(0);
Metafix.asList(record.get(fieldName), a -> a.forEach(recordEntry -> {
final String field = params.get(0);

record.getList(field, a -> a.forEach(recordEntry -> {
if (recordEntry.isHash()) {
record.remove(fieldName);
recordEntry.asHash().forEach((subFieldName, value) -> {
Metafix.add(record, fieldName, new Value(subFieldName));
Metafix.add(record, fieldName, value);
record.remove(field);

recordEntry.asHash().forEach((subField, value) -> {
record.add(field, new Value(subField));
record.add(field, value);
});
}
}));
}
},
hash { // hash-from-array
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
Metafix.asList(record.get(params.get(0)), values -> record.put(params.get(0), Value.newHash(h -> {
for (int i = 1; i < values.size(); i = i + 2) {
h.put(values.get(i - 1).toString(), values.get(i));
final String field = params.get(0);

record.getList(field, a -> record.put(field, Value.newHash(h -> {
for (int i = 1; i < a.size(); i = i + 2) {
h.put(a.get(i - 1).toString(), a.get(i));
}
})));
}
},
add_field {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
insert(InsertMode.APPEND, record, split(params.get(0)), params.get(1));
record.append(params.get(0), params.get(1));
}
},
move_field {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
copy(record, params);
remove(record, split(params.get(0)));
record.copy(params);
record.removeNested(params.get(0));
}
},
copy_field {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
copy(record, params);
record.copy(params);
}
},
remove_field {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
params.forEach(p -> remove(record, split(p)));
params.forEach(record::removeNested);
}
},
format {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
Metafix.asList(record.get(params.get(0)), oldValues -> {
final String field = params.get(0);

record.getList(field, oldValues -> {
final String newValue = String.format(params.get(1), oldValues.stream().toArray());
record.replace(params.get(0), new Value(Arrays.asList(new Value(newValue))));
record.replace(field, new Value(Arrays.asList(new Value(newValue))));
});
}
},
parse_text {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
Metafix.asList(record.get(params.get(0)), a -> a.forEach(v -> {
final String field = params.get(0);

record.getList(field, a -> a.forEach(v -> {
final Pattern p = Pattern.compile(params.get(1));
final Matcher m = p.matcher(v.toString());
if (m.matches()) {
record.remove(params.get(0));
record.remove(field);

/**
* {@code Pattern.namedGroups()} not available as API,
Expand All @@ -139,11 +148,11 @@ public void apply(final Record record, final List<String> params, final Map<Stri
});

if (!value.asHash().isEmpty()) {
Metafix.add(record, params.get(0), value);
record.add(field, value);
}
else {
for (int i = 1; i <= m.groupCount(); i = i + 1) {
Metafix.add(record, params.get(0), new Value(m.group(i)));
record.add(field, new Value(m.group(i)));
}
}
}
Expand All @@ -153,9 +162,9 @@ public void apply(final Record record, final List<String> params, final Map<Stri
paste {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
final String joinChar = options.get("join_char");
insert(InsertMode.REPLACE, record, split(params.get(0)), params.subList(1, params.size()).stream()
.filter(f -> literalString(f) || find(record, split(f)) != null)
.map(f -> literalString(f) ? new Value(f.substring(1)) : Metafix.asList(find(record, split(f)), null).asArray().get(0))
record.replace(params.get(0), params.subList(1, params.size()).stream()
.filter(f -> literalString(f) || record.find(f) != null)
.map(f -> literalString(f) ? new Value(f.substring(1)) : record.findList(f, null).asArray().get(0))
.map(Value::toString).collect(Collectors.joining(joinChar != null ? joinChar : " ")));
}

Expand Down Expand Up @@ -183,33 +192,32 @@ public void apply(final Record record, final List<String> params, final Map<Stri
substring {
@SuppressWarnings("checkstyle:MagicNumber") // TODO: switch to morph-style named params in general?
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
applyToFields(record, params,
s -> s.substring(Integer.parseInt(params.get(1)), Integer.parseInt(params.get(2)) - 1));
record.transformFields(params, s -> s.substring(Integer.parseInt(params.get(1)), Integer.parseInt(params.get(2)) - 1));
}
},
trim {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
applyToFields(record, params, s -> s.trim());
record.transformFields(params, String::trim);
}
},
upcase {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
applyToFields(record, params, s -> s.toUpperCase());
record.transformFields(params, String::toUpperCase);
}
},
downcase {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
applyToFields(record, params, s -> s.toLowerCase());
record.transformFields(params, String::toLowerCase);
}
},
capitalize {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
applyToFields(record, params, s -> s.substring(0, 1).toUpperCase() + s.substring(1));
record.transformFields(params, s -> s.substring(0, 1).toUpperCase() + s.substring(1));
}
},
lookup {
public void apply(final Record record, final List<String> params, final Map<String, String> options) {
applyToFields(record, params, s -> {
record.transformFields(params, s -> {
final Map<String, String> map = buildMap(options, params.size() <= 1 ? null : params.get(1));
return map.getOrDefault(s, map.get("__default")); // TODO Catmandu uses 'default'
});
Expand All @@ -234,145 +242,9 @@ private Map<String, String> fileMap(final String location, final String separato

private static final Pattern NAMED_GROUP_PATTERN = Pattern.compile("\\(\\?<(.+?)>");

private static final String NESTED = "Nested non-map / non-list: ";
private static final String EMPTY = "";
private static final String APPEND = "$append";
private static final String DOT_APPEND = "." + APPEND;
private static final String LAST = "$last";

private static void applyToFields(final Record record, final List<String> params, final Function<String, String> fun) {
final String field = params.get(0);
final Value found = find(record, split(field));
if (found != null) {
remove(record, split(field));

if (fun != null) {
Metafix.asList(found, a -> a.forEach(old -> insert(InsertMode.APPEND, record, split(field), fun.apply(old.toString()))));
}
}
}

private static Value insert(final InsertMode mode, final Value.Hash hash, final String[] fields, final String value) {
final String currentField = fields[0];

if (fields.length == 1) {
mode.apply(hash, currentField, value);
}
else {
final String[] remainingFields = Arrays.copyOfRange(fields, 1, fields.length);
final Value nested = insertNested(mode, hash, value, currentField, remainingFields);
hash.put(currentField, nested);
}

return new Value(hash);
}

private static Value insertNested(final InsertMode mode, final Value.Hash hash, final String value, final String currentField, final String[] remainingFields) {
if (!hash.containsField(currentField)) {
hash.put(currentField, Value.newHash());
}
final Value nested = hash.get(currentField);
final Value result;
if (nested.isHash()) {
result = insert(mode, nested.asHash(), remainingFields, value);
}
else if (nested.isArray()) {
processList(mode, value, remainingFields, nested.asArray());
result = hash.get(currentField);
}
else {
throw new IllegalStateException(NESTED + nested);
}
return result;
}

private static void processList(final InsertMode mode, final String value, final String[] remainingFields, final Value.Array nestedList) {
final Value nestedMap;
switch (remainingFields[0]) {
case APPEND:
nestedList.add(Value.newHash(h -> insert(mode, h, Arrays.copyOfRange(remainingFields, 1, remainingFields.length), value)));
break;
case LAST:
final Value last = nestedList.get(nestedList.size() - 1);
if (last.isHash()) {
insert(mode, last.asHash(), Arrays.copyOfRange(remainingFields, 1, remainingFields.length), value);
}
break;
default:
nestedList.add(Value.newHash(h -> insert(mode, h, remainingFields, value)));
break;
}
}

static Value find(final Value.Hash hash, final String[] fields) {
final String currentField = fields[0];
if (!hash.containsField(currentField) || fields.length == 1) {
return hash.get(currentField);
}
final String[] remainingFields = Arrays.copyOfRange(fields, 1, fields.length);
return findNested(hash, currentField, remainingFields);
}

private static Value findNested(final Value.Hash hash, final String currentField, final String[] remainingFields) {
final Value nested = hash.get(currentField);

// TODO: array of maps, like in insertNested

if (nested.isHash()) {
return find(nested.asHash(), remainingFields);
}

throw new IllegalStateException(NESTED + nested);
}

private static Value remove(final Value.Hash hash, final String[] fields) {
final String currentField = fields[0];
if (fields.length == 1) {
hash.remove(currentField);
}
if (!hash.containsField(currentField)) {
return new Value(hash);
}
final String[] remainingFields = Arrays.copyOfRange(fields, 1, fields.length);
return removeNested(hash, currentField, remainingFields);
}

private static Value removeNested(final Value.Hash hash, final String currentField, final String[] remainingFields) {
final Value nested = hash.get(currentField);
if (nested.isHash()) {
return remove(nested.asHash(), remainingFields);
}
throw new IllegalStateException(NESTED + nested);
}

private static void copy(final Record record, final List<String> params) {
final String oldName = params.get(0);
final String newName = params.get(1);
final Value value = find(record, split(oldName));
Metafix.asList(value, vs -> vs.forEach(v -> insert(InsertMode.APPEND, record, split(newName), v.toString())));
}

static String[] split(final String s) {
return s.split("\\.");
}

private enum InsertMode {
REPLACE {
@Override
void apply(final Value.Hash hash, final String field, final String value) {
hash.put(field, new Value(value));
}
},
APPEND {
@Override
void apply(final Value.Hash hash, final String field, final String value) {
final Value oldValue = hash.get(field);
final Value newValue = new Value(value);
hash.put(field, oldValue == null ? newValue : Metafix.merged(oldValue, newValue));
}
};
abstract void apply(Value.Hash hash, String field, String value);
}
private static final String DOT_APPEND = "." + Value.Hash.APPEND_FIELD;

abstract void apply(Record record, List<String> params, Map<String, String> options);

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ protected boolean test(final Record record, final String fieldName, final Predic
};

boolean testStream(final Record record, final String fieldName, final Predicate<Stream<Value>> p) {
final Value value = FixMethod.find(record, FixMethod.split(fieldName));
return value != null && p.test(Metafix.asList(value, null).asArray().stream());
final Value value = record.find(fieldName);
return value != null && p.test(value.asList(null).asArray().stream());
}

public boolean test(final Record record, final FixPredicate p, final List<String> params) {
Expand Down
Loading

0 comments on commit 73a0563

Please sign in to comment.