How can I create a Bacon.Property representing a property in a referenced object? - frp

I have started playing with Bacon.js, and I have come across a problem I can't find any example for.
I have a set of nodes, which may reference other nodes.
It looks like this in imperative code:
alice = { name: "Alice" }
bob = { name: "Bob" }
carol = { name: "Carol" }
alice.likes = bob
bob.likes = carol
alice.likes.name //=> "Bob"
bob.name = "Bobby"
alice.likes.name //=> "Bobby"
alice.likes = carol
alice.likes.name //=> "Carol"
Now, I would like to have a Property for alice.likes.name, which has to change
whenever alice.likes points to a different object, or the name property of the
current object in alice.likes changes.
I have come up with the code below (LiveScript syntax), which correctly logs 3 messages: Bob, Bobby, Carol.
I'm using Bus for testing purposes.
mkBus = (initialValue) ->
bus = new Bacon.Bus()
property = bus.toProperty(initialValue)
property.push = (newValue) -> bus.push(newValue)
property
alice = { pName: mkBus("Alice"), pLikes: mkBus(null) }
bob = { pName: mkBus("Bob"), pLikes: mkBus(null) }
carol = { pName: mkBus("Carol"), pLikes: mkBus(null) }
alice.pLikes.onValue (person) ->
if person
person.pName.onValue (vName) ->
console.log vName
alice.pLikes.push(bob)
bob.pLikes.push(carol)
# Change name
bob.pName.push("Bobby")
# Change reference
alice.pLikes.push(carol)
Question: How can I make a Property that represents the name of alice.likes.name?
I.e:
nameOfAlicesFavourite.onValue (vName) ->
console.log vName
I'm new to FRP, so let me know if I'm doing something horribly wrong.

Thanks #Bergi for pointing me to flatMap.
flatMap creates a new stream for every event in the source. I used flatMapLatest, so that only the name changes from the latest liked person are transmitted on the output stream.
Here's the code:
nameOfAlicesFavourite = alice.pLikes.flatMapLatest (person) ->
if person
person.pName
else
Bacon.never!

Related

How to convert text to JSON in JavaScript

My dataset looks like the below:
Make: AUSTIN
Models:
1000
1300
Make: Ferrari
Models:
458
La Ferrari
I will like this in a JSON format, as below:
{
make: "AUSTIN",
models: [
{model: "1000"},
{model: "1300"}
]
},
{
make: "Ferrari",
models: [
{model: "458"},
{model: "La Ferrari"}
]
}
It's a very large dataset so I can't do it manually.
Looked around online and didn't find anything suitable.
Thanks in advance!
As far as I understand your question, I would like to answer it.
You can do something like this.
function getFormatted(s){
const total = []
const lines = s.split('\n');
let index = 0;
while(lines[index]){
const make = lines[index];
const obj = {
make: make.replace('Make: ',''),
models: []
}
// index + 1 will be 'Models:'
let modelCurrentIndex = index + 2;
let currentModel = lines[modelCurrentIndex];
// Check until the next occurrence of 'Make: '
while(currentModel && !currentModel.startsWith("Make:")){
obj.models.push({model: currentModel});
modelCurrentIndex += 1;
currentModel = lines[modelCurrentIndex];
}
index = modelCurrentIndex;
total.push(obj);
}
return JSON.stringify(total);
}
Sample Web Page would be like this
After calling this function,
Explanation:
The First Index of the lines should be identified as 'make' and that index + 2 will be identified as the starting point of Models.
The while loop will add the models to the array in the object until it identifies the line that starts with 'Make:'. After that, the index is moved and the process gets repeated.
Make sure you are entering the values with a line break!

Editing the get_string function in Game Maker Studio 2

Everything works yet when I get prompted up to enter my name it looks like an error. Is there anyway I can edit it?
I am new to GameMaker, this is just my personal work for fun.
I have been looking online for a solution but it does not seem to be anywhere, I not sure if it's possible.
The following is the code that I am referring to.
if (currentHealth <= 0) {
name = get_string("Please enter your name: ","Anonymus");
highscore_add(name, global.points);
room_goto(GAMEOVER);
}
Maybe try "get_string_async()"
get_string should only be used for debugging. if you use get_string_async() your code will look like this
Create Event:
async = -1
input = 0
Step Event:
if (currentHealth <= 0 && input == 0) {
name = get_string_async("Please enter your name: ","Anonymus");
input = 1
}
Async_Dialogue Event:
var i_d = ds_map_find_value(async_load, "id");
if i_d == async
{
if ds_map_find_value(async_load, "status")
{
name = ds_map_find_value(async_load, "result");
highscore_add(name, global.points);
room_goto(GAMEOVER);
}
This works fine for me
If you want an "input field" (term to look for), you can use keyboard_string. For example,
Create:
keyboard_string = "";
Step:
if (keyboard_check_pressed(vk_enter)) {
input = keyboard_string;
// ... do something with `input`
}
Draw:
draw_text(x, y, keyboard_string);
Or a slightly less basic example that I made in 2013.

How to add variable on a set (Alloy)

module carona
open util/ordering[Time]
sig Time {}
sig Car {
passengers : set Passager
}
one sig UFCG{
students: set Student -> Time
}
abstract sig Student{
region: Region -> Time
}
sig Owner extends Student{
ownerCar : Car
}
sig Passager extends Student{
}
abstract sig Region{ }
one sig Norte,Sul,Leste,Oeste,Centro extends Region{ }
fact Owner{
all o: Owner | #o.ownerCar = 1
}
fact Passager{
all p:Passager | one p.~passengers
}
fact Car{
all c:Car| one c.~ownerCar
all c:Car| #c.passengers <= 4
all c:Car| c.passengers.region=(c.~ownerCar).region
}
fact UFCG {
all passager: Passager, ufcg : UFCG, t:Time | passager in (ufcg.students).t
all owner: Owner, ufcg: UFCG,t:Time | owner in (ufcg.students).t
}
fact Traces{
init[first]
all pre: Time-last | let pos = pre.next |
lone u:UFCG|
some s:Student|
addStudent[s,u,pre,pos]
}
pred init[t:Time]{
one u:UFCG | no (u.students).t
}
pred addStudent[s:Student, u: UFCG, before, after: Time]{
(s !in (u.students).before)
(u.students).after = (u.students).before + s
}
After I run and show the instances created over time, my pred to add Passenger doesn't seem to work, nothing changes or even create. How do i properly add items on a set?
My program, when run, does not show any instance. That is, I can not add anything over time.
Well, for one thing, in the UFCG fact the first quantified formula says that at every time every passenger is in the UFCG student set, this preventing any change in that set.

How to I reference an array member in Ruby?

Given this array in Ruby:
myarray = [name: "John", age: 35]
How do I refer to the age?
I tried myarray[:age] but got an error can't convert Symbol into Integer
Update:
I was trying to simplify my question by extracting what I thought my problem is. I may not understand completely.
I'm experimenting with Dashing and trying to send a number to a meter widget. I've created a variable, 'response_raw' and am trying to send it in the third send event. Here's my code:
SCHEDULER.every '1m', :first_in => 0 do
# Get checks
url = "https://#{CGI::escape user}:#{CGI::escape password}#api.pingdom.com/api/2.0/checks"
`enter code here`response = RestClient.get(url, {"App-Key" => api_key})
response = JSON.parse(response.body, :symbolize_names => true)
if response[:checks]
checks = response[:checks].map { |check|
if check[:status] == 'up'
state = 'up'
last_response_time = "#{check[:lastresponsetime]}ms"
response_raw = check[:lastresponsetime]
else
state = 'down'
last_response_time = "DOWN"
response_raw = 0
end
{ name: check[:name], state: state, lastRepsonseTime: last_response_time, pt: response_raw }
}
else
checks = [name: "pingdom", state: "down", lastRepsonseTime: "-", pt: 0]
end
checks.sort_by { |check| check['name'] }
send_event('pingdom', { checks: checks })
send_event('pingdom-meter', { value: checks[:pt] })
end
In CoffeeScript [name: "John", age: 35] is an array containing single object with two properties (name and age).
Here is how it'll look in plain JavaScript:
myarray = [
{
name: "John",
age: 35
}
];
So, answering your question, to access an age you should take the first element of an array and then reference an age property:
myarray[0].age
or
myarray[0]['age']
But, judging from your question, your're probably using wrong data structure. Why don't you want to use a plain object instead of an array?
person = name: "John", age: 35
console.log "#{person.name}'s age is #{person.age}"
Update
It looks like your question is actually about Ruby and not about CoffeeScript. Though, my answer will remain the same.
To access an age you should take the first element of an array and then reference an age property:
myarray[0][:age]
Since myarray is an array, Ruby expects an integer index, but you're giving it symbol :age instead.
I finally figured it out with Leonid's help. Thank you.
I changed:
send_event('pingdom-meter', { value: checks[:pt] })
to
send_event('pingdom-meter', { value: checks[0][:pt] })

how to generate a string from complex format similiar to regular expression?

We know String.format() can accept format with such style:
%[argument_index$][flags][width][.precision]conversion
which is well known as C printf() format, and introduced in java 1.5.
My task is, generating complex format including repeated or optional parameters.
For example, with the format:
select %1 from %2 where %3 and give %1->'*' %2->'users' %3->'age>20'
it returned:
select * from users where age>20
the format can be supported by Stirng.format().
However, I expect a format similar to:
select %1{, } from (%2(as %3)){,} (where %4 (and %5))?
when: %1->'*', %2->'users' %3->null, %3->'age>20'
it returned:
select * from users where age>20
when: %1->Stirng{'name','age'} , %2->'users' %3->'u', %4->'age>20', %5->null
it returned:
select name, age from users as u where age>20
when: %1->Stirng{'name','age'} , %2->'users' %3->'u', %4->null, %5->null
it returned:
select name, age from users as u
when: %1->Stirng{'name','age'} , %2->String{'users','order'} %3->{'u','o'}, %4->'age>20', %5->'u.id=o.userid'
it returned:
select name, age from users as u,orders as o where age>20 and u.id=o.userid
I think now you may understand my meanings. Are there a mature library to do such complex 'anti-regexp' work?
Maybe you are looking for a CustomFormatProvider?
class SqlFormatter:IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
return this;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
StringBuilder concat = new StringBuilder();
string[] formatParts = format.Split(':');
switch (formatParts[0])
{
case "sqlfield":
string sep = "";
if (formatParts.Length>1)
{
sep = formatParts[1];
}
string[] fields = (string[]) arg;
concat.Append(fields[0]);
for (int fieldIndex = 1; fieldIndex < fields.Length; fieldIndex++)
{
concat.Append(sep);
concat.Append(fields[fieldIndex]);
}
break;
case "sqltables":
concat.Append(arg.ToString());
break;
default:
break;
}
return concat.ToString();
}
}
Use it like this:
String sql = String.Format(
new SqlFormatter()
, "select {0:sqlfield:,} from {1:sqltables} "
, new string[]{"name","lname"}
, "person" );
Will give:
"select name,lname from person "
I'll leave the rest of the implementation (and robustness etc) to you...

Resources