XST 19: A Bit of Code
Let’s work on those new operations a bit.
Right. Got a little more time today. Let’s start with “element projection”. Sure wish these people would think of shorter names. Begin with a test.
_:test("ElementProject", function()
local s = XSet():addAt("hi","greeting"):addAt("hello","greeting"):addAt("bye","farewell")
_:expect(s:elementProject("farewell")).is("bye")
_:expect(s:elementProject("greeting")).is(nil)
_:expect(s:elementProject("mumble")).is(nil)
end)
Looks like a good test to me. I expect there is no such method:
28: ElementProject -- Tests:390: attempt to call a nil value (method 'elementProject')
Woot!
I swear I just typed this in and it worked.
function XSet:elementProject(scope)
local found = false
local result = nil
for e,s in self:elements() do
if s==scope then
if not found then
result = e
found = true
else
result = nil
end
end
end
return result
end
Tests run. I wonder if that could be simpler.
function XSet:elementProject(scope)
local found = 0
local result = nil
for e,s in self:elements() do
if s==scope then
result = e
found = found + 1
end
end
return found==1 and result or nil
end
I’ll take it. Commit: ‘elementProject` method.
I am so inclined to give that a shorter name. Anyway, how about those scope thingies. Scope Restrict, was it?
_:test("ScopeRestrict", function()
local s = XSet():addAt("a","x"):addAt("b","y"):addAt("c","y"):addAt("d","z")
local r = XSet():addAt("x",NULL):addAt("y",NULL):addAt("w",NULL)
local t = r:scopeRestrict(r)
_:expect(t:card()).is(3)
_:expect(t:hasAt("a","x")).is(true)
_:expect(t:hasAt("b","y")).is(true)
_:expect(t:hasAt("c","y")).is(true)
_:expect(t:hasntAt("d","z")).is(true)
end)
I think that says it. Method doesn’t exist yet:
29: ScopeRestrict -- Tests:398: attempt to call a nil value (method 'scopeRestrict')
function XSet:scopeRestrict(B)
return self:select(function(_ignored,aScope)
return B:exists(function(bElement,_ignored)
return bElement==aScope
end)
end)
end
This worked as soon as I changed the test to be correct:
local t = s:scopeRestrict(r)
So that’s good.
Shall we do Set Scope Restrict too, while we’re at it? Might as well, I seem to have the knack right now. Test’ll be a pain. Maybe I have some sample data up in the tests.
_:test("SetScopeRestrict", function()
local S = XSet:on(CSVSet(CSVnames, CSVminidata))
local r = XSet():addAt("first_name",NULL):addAt("last_name",NULL)
local t = S:setScopeRestrict(r)
local first, second, third
for e,s in t:elements() do
if first==nil then
first = e
elseif second==nil then
second = e
else
third = e
end
end
_:expect(first:card()).is(2)
_:expect(second:card()).is(2)
_:expect(third:card()).is(2)
_:expect(first:elementProject("first_name")).is("James")
end)
Decided that CSV data should be good for something.
Method doesn’t exist:
30: SetScopeRestrict -- Tests:409: attempt to call a nil value (method 'setScopeRestrict')
Ah, but I can’t rely on the order of the elements. Let me try something:
_:test("SetScopeRestrict", function()
local S = XSet:on(CSVSet(CSVnames, CSVminidata))
local r = XSet():addAt("first_name",NULL):addAt("last_name",NULL)
local t = S:setScopeRestrict(r)
local firsts = {"James","Josephine","Art"}
local lasts = {"Butt","Darakjy","Venere"}
for e,s in t:elements() do
_:expect(e:card()).is(2)
local first = e:elementProject("first_name")
_:expect(firsts).has(first)
local last = e:elementProject("last_name")
_:expect(lasts).has(last)
end
end)
Anyway the function worked first time:
function XSet:setScopeRestrict(B)
result = XSet()
for record,scope in self:elements() do
result:addAt(record:scopeRestrict(B),scope)
end
return result
end
Can I do that with reduce? Better commit first, I forgot. Commit: scopeRestrict and setScopeRestrict operators.
function XSet:setScopeRestrict(B)
return self:reduce(XSet(), function(result,record,scope)
return result:addAt(record:scopeRestrict(B),scope)
end)
end
That passes also. Commit: setScopeRestrict uses reduce.
Let’s sum up and get outa here, my honey’s home.
Summary
Three new operators on speculation that they’ll be useful in building indexes. We’ll see.
They went in nicely. It’s becoming clear that creating sets is harder than manipulating them. I need some work on the Making side of this app.
I’m pleased to be able to use reduce
, though I am concerned that functions using it are a bit harder to write. Relatedly there are a few functions with their own elements() do
and it seems those could be boiled down into some other generic. I’ll try to remember to look into that.
For now, more than enough. See you next time!