Building Object in Rebol dynamically - oop

This works:
>> Oblock: [FirstName: ""
[ LastName: ""
[ BirthDate: ""]
== [FirstName: ""
LastName: ""
BirthDate: ""
]
>> Person: Make Object! OBlock
>> Person
>> probe Person
make object! [
FirstName: ""
LastName: ""
BirthDate: ""
]
>> Person/FirstName
== ""
>> Person/FirstName: "John"
== "John"
But this doesn't work
>> List: ["Id" "FirstName" "LastName"]
== ["Id" "FirstName" "LastName"]
>> Person: []
== []
>> foreach attribute List [
[ Append Person to-word rejoin [attribute {: ""}]
[ ]
== [Id: "" FirstName: "" LastName: ""]
>> Person/FirstName
** Script Error: Invalid path value: FirstName
** Where: halt-view
** Near: Person/FirstName
>>
Why ?

There are so many ways to do this, but here's one way that adheres closely to the way you seem to envision it:
list: [ "Id" "FirstName" "LastName" ]
person: []
forall list [
repend person [to-set-word first list ""]
]
person: make object! person
print person/FirstName
; == ""
In a traditional programming language, you do something like this to set the value of a variable:
x = 3;
In REBOL, you do this:
x: 3
In a traditional programming language, = is an operator, but : is not an operator in REBOL. It is a part of the word itself. This is a very important distinction, and it's why what you tried to do above did not work. x: is a set-word!, and to make one from a string you have to use to-set-word.
to-set-word "x"
; == x:
Also, you seem to be confusing objects and blocks. This is an object:
person: make object! [ first-name: "Jasmine" last-name: "Byrne" ]
This is a block:
person: [ first-name "Jasmine" last-name "Byrne" ]
They are not the same.

The reboltutorial's "person" block looks like exactly same in appearence with Geogory's.
But in fact person/1(the block) is "id: " in the first post witch type is a string!, id is just only part of it.
in second post, person/1 is "id:", witch type is set-word!.
This is the essential difference of them.

Related

Karate contains only shortcut fails in v1.2.0

According to Karate documentation for contains short-cuts The following match arguments should work and do the same:
#test_contains_only
Scenario: Test contains only shortcut
* def expected = [ "a", "b", "c", "d" ]
* def to_match = { "properties": { "additional_information": "Some put-updated info", "types": [ "a", "b", "c", "d" ] } }
* print to_match.properties.relation_types
# This will pass
* match to_match.properties contains deep
"""
{
"additional_information": "Some put-updated info",
"types": [ "a", "b", "c", "d" ]
}
"""
# This will pass
* match to_match.properties.types == '#(^^expected)'
# This will fail
* match to_match.properties contains deep
"""
{
"additional_information": "Some put-updated info",
"types": '#(^^expected)'
}
"""
When executing the above, I get this error:
* match to_match.properties contains deep
"""
{
"additional_information": "Some put-updated info",
"types": '#(^^expected)'
}
"""
match failed: CONTAINS_DEEP
$ | actual does not contain expected | all key-values did not match, expected has un-matched keys - [types] (MAP:MAP)
{"additional_information":"Some put-updated info","types":["a","b","c","d"]}
{"additional_information":"Some put-updated info","types":"#(^^expected)"}
$.types | actual does not contain expected | actual array does not contain expected item - #(^^expected) (LIST:STRING)
["a","b","c","d"]
'#(^^expected)'
$.types[3] | data types don't match (STRING:LIST)
'd'
["a","b","c","d"]
$.types[2] | data types don't match (STRING:LIST)
'c'
["a","b","c","d"]
$.types[1] | data types don't match (STRING:LIST)
'b'
["a","b","c","d"]
$.types[0] | data types don't match (STRING:LIST)
'a'
["a","b","c","d"]
In my opinion, using '#(^^expected)' doesn't work as expected. Or is it happening because I'm using match to_match.properties contains deep together with the ^^ (contains only shortcut)?
I'm using Karate v1.2.0. The same scenario doesn't fail in v1.0.1.
See if this is fixed in 1.2.1.RC2: https://github.com/karatelabs/karate/issues/2007
Else please file an issue. Ideally a PR ;)

How to use OR operator with contains to assert/ match in Karate [duplicate]

I am trying to use a match contains to verify my schema response and data types and sometimes it returns a null and sometimes it will return a string, as an example. I am trying the following but I am getting the assertion failed because it did not evaluate to true.
I am trying the following:
* match each $response.data.Results contains
"""
{
"providerID": '#number',
"firstName": "#? _ == '#string' || _ == '#null'",
"lastName": '#string',
"mI": "#? _ == '#string' || _ == '#null'",
"title": '#string',
"name": '#string',
"nameLFMT": '#string',
"status": '#string',
"specialties": '#array',
"locations": '#array',
"institutions": '#array',
"acceptNewPatient": '#string',
"imageUri": '#string',
"nearestLatitude": '#number',
"nearestLongitude": '#number'
}
"""
The data returned for "firstName" for example is "firstName":null,
Prior to the match each I am sending this:
Scenario: SearchResults
#Verify 200 response status returned
Given text query =
"""
{
Results: getSearchResults(searchLatitude:"48.942833",
searchLongitude: "-119.984549",
providerType: "Primary Care Physicians",
sortBy: "distance",
maxDistance:"600",
skip: 0,
take: 10) {
providerID
firstName
lastName
mI
title
name
nameLFMT
status
specialties
locations
institutions
acceptNewPatient
imageUri
nearestLatitude
nearestLongitude
}
}
"""
And request { query: '#(query)' }
When method post
Then status 200
I am not defining the schema, I have yet to figure out how to do this so I am not sure if that is my issue. I know this is probably how I should do this but I'm still learning.
Thanks for any help.
Ok I see one problem here:
"firstName": "#? _ == '#string' || _ == '#null'"
That's not going to work. The part that follows the #? has to be a valid JavaScript expression. This may be hard to understand if you are not familiar with JS but #string and friends are specific to the Karate match keyword and not something that works in JavaScript.
So what the above line is doing is checking if the value of firstName is equal to the literal string #string.
Fortunately Karate has a solution: (refer doc for 'fuzzy matching'):
"firstName": "##string"
Which is a convenience, the double ## means 'optional' that will match for both a string or null.
EDIT: for advanced cases, please read this: https://stackoverflow.com/a/50350442/143475

Openrefine: split with regex gives strange result

I applied the GREL expression "value.split(/a/)" to some cells:
abcdef -> [ "", "bcdef" ]
bcdefa -> [ "bcdef" ]
badef -> [ "b", "def" ]
I can't understand why the first cell gives me a "" element in the resulting table. Is it a bug?
Thanks!
I don't know Java enough to comment on the source code for this function, but according to one of the developers of Open Refine this behavior is normal (edit : More details in Owen's comment, below). This is why there are other functions to split a string.
value.smartSplit(/a/), for example, gives a more consistent result when sep is at the begining or at the end of the string:
row value value.smartSplit(/a/)
1. abcdef [ "", "bcdef" ]
2. bcdefa [ "bcdef", "" ]
3. badef [ "b", "def" ]
This is the same result as using partition() with the omitfragment = true option enabled:
row value value.partition(/a/, true)
1. abcdef [ "", "bcdef" ]
2. bcdefa [ "bcdef", "" ]
3. badef [ "b", "def" ]

How to retrieve a function from a series of functions and call it

I'm trying to create a dispatcher of functions in Rebol 3, so that for each string the program receives there's an associated function to be called.
For example:
handlers: make map! [
"foo" foo-func
"bar" bar-func
]
where foo-func and bar-func are functions:
foo-func: func [ a b ] [ print "foo" ]
bar-func: func [ a b ] [ print "bar" ]
The idea is to select the function starting from the string, so:
f: select handlers "foo"
so that executing f is the same as executing foo-func and then call f with some arguments:
f param1 param2
I tried quoting the words in the map!, or using get-words but without success.
Using a get-word! at the console, without passing through a map! it works:
>> a: func [] [ print "Hello world!" ]
>> a
Hello world!
>> b: :a
>> b
Hello world!
Any help appreciated.
select handlers "foo" only get the word foo-func:
f: select handlers "foo"
probe f ;will get: foo-func
You need to get its content:
f: get f
f 1 2 ;will print "foo"
Or more compact:
f: get select handlers "foo"
It's better to actually have the reference to the function in the map, rather than a word that refers to the function. If you store a word then you have to make sure the word is bound to an object which has a reference to that function, like this:
handlers: object [
foo-func: func [ a b ] [ print "foo" ]
bar-func: func [ a b ] [ print "bar" ]
]
handler-names: map [
"foo" foo-func
"bar" bar-func
]
apply get in handlers select handler-names name args
But if you just have a reference to the function in your map, you don't have to do the double indirect, and your code looks like this:
handlers: map reduce [
"foo" func [ a b ] [ print "foo" ]
"bar" func [ a b ] [ print "bar" ]
]
apply select handlers name args
Cleaner code, and more efficient too. Or if you're careful enough, like this:
handlers/(name) a b
The path method above will also work if you want the code to do nothing if there is no handler - common in cases where you have optional handlers, such as in GUIs.
You can even have more than one reference to the same function with different key names. You don't have to assign functions to words, they're just values. You can also use the path method to collect the handlers in the first place, saving a reduce.
handlers: make map! 10 ; preallocate as many entries as you expect
handlers/("foo"): func [ a b ] [ print "foo" ]
handlers/("bar"): func [ a b ] [ print "bar" ]
handlers/("baz"): select handlers "bar" ; multiple references
That path syntax is just another way to call poke, but some prefer it. We have to put the string values in parens because of a (hopefully temporary) syntax conflict, but within those parens the string keys work. It's a faster alternative to do select or poke.
foo-func in your map is just an unevaluated word
>> type? select handlers "foo"
== word!
You should first create your functions and then reduce the block, you use for creating your handler map so
handlers: make map! reduce [
"foo" :foo-func
"bar" :bar-func
]
then you have functions inside your map
>> type? select handlers "foo"
== function!
Try:
....
f: do select handlers "foo"
....

Rebol switch and type?

Why do I have to cast typeof to string with switch to make it work ?
This doesn't work:
typeof: type? get 'optional
switch typeof [
word! [
print "word"
]
string! [
print "string"
]
]
This works:
typeof: type? get 'optional
switch to-string typeof [
"word" [
print "word"
]
"string" [
print "string"
]
]
switch type?/word :optional [
word! [ print "word" ]
string! [ print "string" ]
]
OR
switch type? :optional reduce [
word! [ print "word" ]
string! [ print "string" ]
]
The reason is that the REBOL doesn't reduce ("evaluate") the cases in the switch statement. Without the /word refinement, the type? function returns a datatype!, but the switch statement tries to match this against a word!, and it fails.
I realize this might be confusing, so your best bet is either to convert the type to a string (as you did), or use one of the two idioms I've suggested. I prefer the first one, using type?/word.