metafacture-tutorial

Lesson 6: More Fix concepts

We already learned about simple Fixes (or Fix Functions) but there are three additional concepts in Fix selector, conditionals and binds. These Fix concepts were introduced by Catmandu (see functions, selector, conditionals and binds). But be aware Metafacture Fix does not support all of the specific functions, selectors, conditionals and binds from Catmandu. Check the documentation for an full overview of the supported fix functions.

Additional concepts

The following code snippet shows examples of eachs of these concepts:

# Simple fix function

add_field("hello", "world")
remove_field("my.deep.nested.junk")
copy_field("stats", "output.$append")

# Conditionals

if exists("error")
  set_field("is_valid", "no")
  log("error")
elsif exists("warning")
  set_field("is_valid", "yes")
  log("warning")
else
  set_field("is_valid", "yes")
end

# Binds - Loops

do list(path: "foo", "var": "$i")
  add_field("$i.bar", "baz")
end

# Selector
if exists("error")
   reject()
end

We already got to know simple fixes aka Functions. They are used to add, change, remove or otherwise manipulate elements. Simple fixes were introduced in Lesson 3.

The other three concepts help when you intend to use more complex transformations:

Conditionals are used to control the processing of fix functions. The included fix functions are not process with every workflow but only under certain conditions.

Selectors can be used to filter the records you want.

Binds are wrappers for one or more fixes. They give extra control functionality for fixes such as loops. All binds have the same syntax:

do Bind(params,…)
   fix(..)
   fix(..)
end

Conditionals

Conditionals are a common concept in programming and scripting languages. They control processes, in our scenario: transformations, with regard to specific requirements.

e.g. we have records some of them are of type book:

---
name: "The 13 1/2 lives of Captain Bluebear"
medium: "Book"
author: "Walter Moers"
language: "eng"

---
name: "The 13 1/2 lives of Captain Bluebear"
medium: "eBook"
author: "Walter Moers"
language: "eng"

---
name: "Die 13½ Leben des Käpt’n Blaubär"
medium: "Book"
author: "Walter Moers"
language: "ger"

---
name: "The 13 1/2 lives of Captain Bluebear"
medium: "Audio Book"
author: "Walter Moers"
narrator: "Bronson Pinchot"
language: "eng"

---
name: "Käpt'n Blaubär - Der Film"
medium: "Movie"
author: "Walter Moers"
director: "Hayo Freitag"
language: "ger"

If we want to add an element e.g. type for every record. Then we simply use the fix function add_field("type","BibliographicResource")

But if you want to add more specific type depending on the type, then we use contitionals:

e.g.:

only add_field("type","BibliographicResource") if the medium contains Book:

if all_contain("medium","Book")
    add_field("type","BibliographicResource")
end

or only if medium is exact:

if all_equal("medium","Book")
    add_field("type","BibliographicResource")
end

Conditionals usually have the same syntax pattern:

if conditional("Parameter1","Parameter2")
  fix-functions
end

If you want to add transformations for all that do not meet the condition with unless:

unless all_equal("medium","Book")
    add_field("type","Other")
end

You can also use conditionals if they meet the requirements and handle all others differently with else:

if all_equal("medium","Book")
    add_field("type","BibliographicResource")
else
    add_field("type","Other")
end

You can also use conditionals if they meet the requirements and handle all others differently with an additionl conditionals with elsif and the rest with else:

if all_equal("medium","Book")
    add_field("type","BibliographicResource")
elsif all_contain("medium","Audio")
    add_field("type","AudioResource")
elsif all_match("medium",".*Movie.*")
    add_field("type","AudioVisualResource")
else
    add_field("type","Other")
end

Metafacture supports lots of conditionals, find a list of all of them here.

Hint: Some conditionals have variations with all_ or any_ while they behave in the same way if you process them on simple string-elements. They also can be used with arrays/lists then the conditional has different out-come depending on the fact that all (all_) or at least one (any_) value of an array matches the requierement.

Selectors

At the moment Metafacture Fix only supports one of Catmandus selectors: reject. With reject you can kick out records that you do not want to process:

if all_contain("medium","Book")
    reject()
end

This Fix used with our example above kicks out all records containing the word Book.

Selectors work in combination with conditionals to define the conditions that you want to kick out.

For the supported selectors see: https://github.com/metafacture/metafacture-documentation/blob/master/Fix-function-and-Cookbook.md#selectors

Binds

As mentioned above Binds* are wrappers for one or more fixes. They give extra control functionality for fixes such as loops. All binds have the same syntax:

do Bind(params,…)
   fix(..)
   fix(..)
end

The most commonly used is do list. It allows to iterate over each element of an array.

If we have a record:

---
colours:
 - red
 - yellow
 - green

and you use the fix

set_array("result") # To create a new array named result

upcase("colours[].*")
append("colours[].*"," is a nice color")
copy_field("colours[].*","result.$append")

It results in:

---
colours:
- "RED is a nice color"
- "YELLOW is a nice color"
- "GREEN is a nice color"
result: "RED is a nice color"
result: "YELLOW is a nice color"
result: "GREEN is a nice color"

If you want to only change it, under a certain condition:

if any_equal("colours[]","green")
  set_array("result[]") # To create a new array named result
  upcase("colours[].*")
  append("colours[].*"," is a nice color")
  copy_field("colours[].*","result[].$append")
end

This still transforms the all elements of an array because the conditional tests all elements not each individually. To only tranform and copy the value green to an X you have to use the do list-Bind:

do list(path:"colours[]","var":"$i")
    if any_equal("$i","green")
        set_array("result[]") # To create a new array named result
        upcase("$i")
        append("$i"," is a nice color")
        copy_field("$i","result[].$append")
    end
end

See this example here in the playground.

TO BE CONTINUED …

TODO: Add Excercises.

Next lesson: 06 Metafacture CLI