Generating an href value and route pattern from a common string - f#

In mvc-movie-giraffe I have a line like this in a view to generate a link to an edit page:
a [ _href ("/Movies/Edit/" + (string elt.Id)) ] [ encodedText "Edit" ]
Then where I setup the routes, I have the following:
routef "/Movies/Edit/%i" edit_handler
It would be nice to factor out that string "/Movies/Edit/".
So I added it to a Urls module along with some others:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
For the href value:
a [ _href ("/Movies/Edit/" + (string elt.Id)) ] [ encodedText "Edit" ]
we can do this instead:
a [ _href (sprintf (Printf.StringFormat<int->string>(Urls.movies_edit)) elt.Id) ] [ encodedText "Edit" ]
and for the route case:
routef "/Movies/Edit/%i" edit_handler
we can do this:
routef (PrintfFormat<obj, obj, obj, obj, int>(Urls.movies_edit)) edit_handler
And this does appear to work!
My question is, is there a better way? Perhaps something more concise? The above is a bit syntax heavy. Or is there already some established best practice around this?
I looked through the Giraffe samples and didn't notice anything like this technique being used.
Update - Approach #2
Here's one approach. Basically, factor out those longer expressions as well:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
let movies_edit_href = sprintf (Printf.StringFormat<int->string>(movies_edit))
let movies_edit_route = PrintfFormat<obj, obj, obj, obj, int>(movies_edit)
And then reference them in views:
a [ _href (Urls.movies_edit_href elt.Id) ] [ encodedText "Edit" ]
and when setting up routes:
routef Urls.movies_edit_route edit_handler
Update - approach #3
With approach #2, I ended up with this:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
let movies_edit_href = sprintf (Printf.StringFormat<int->string>(movies_edit))
let movies_edit_route = PrintfFormat<obj, obj, obj, obj, int>(movies_edit)
let movies_details = "/Movies/Details/%i"
let movies_details_href = sprintf (Printf.StringFormat<int->string>(movies_details))
let movies_details_route = PrintfFormat<obj, obj, obj, obj, int> (movies_details)
let movies_delete = "/Movies/Details/%i"
let movies_delete_href = sprintf (Printf.StringFormat<int->string>(movies_delete))
let movies_delete_route = PrintfFormat<obj, obj, obj, obj, int> (movies_delete)
There's some repetition there so I defined these extensions:
type String with
member this.route = PrintfFormat<obj, obj, obj, obj, int>(this)
member this.href = sprintf (Printf.StringFormat<int->string>(this))
Now, the Urls module is just:
module Urls =
let movies = "/Movies"
let movies_create = "/Movies/Create"
let movies_edit = "/Movies/Edit/%i"
let movies_details = "/Movies/Details/%i"
let movies_delete = "/Movies/Details/%i"
And then to get the href string for movies_edit:
a [ _href (Urls.movies_edit.href elt.Id) ] [ encodedText "Edit" ]
And similar for the route:
routef Urls.movies_edit.route edit_handler

I definitely do this at work to share url route templating.
type Route<'t> = PrintfFormat<obj, obj, obj, obj, 't>
let Details = Route<Guid> ("/Details/%O")
and then reference this in my route handlers as well as in my views to generate routes. There are a few caveats though:
for values (like let bindings), you can't leave the generic parameters of the PrintfFormat type 'open'. So they get unified to obj, which is what you're seeing.
if you need to keep the generic parameters open for some reason, the workaround is to convert the value to an inline function with a unit parameter, then invoke that function at each callsite:
let inline Details () = PrintfFormat<_,_,_,_,Guid> "/Details/%O"
this gets past the 'value restriction' that many ML-family languages have. You can look up that term for literature on why the generic parameters have to remain open on a value-binding.

Related

how to pass additional parametes to spider parse function in scrapy during web scraping

I am trying to pass additional information to the parse function but it is giving a type error.
TypeError: parse() got an unexpected keyword argument 'body'
i am unable to resolve this issue.
"""
return [scrapy.Request(url=website.search_url.format(prod), callback=self.parse,
cb_kwargs = {"body":website.body_xpath,"product_list":website.products_list_xpath,
"names":website.products_name_xpath,"selling_price":website.selling_price_xpath,
"market_price":website.market_price_xpath}) for website in websites for prod in modified_products]
def parse(self, response):
body = response.cb_kwargs.get("body")
product_list = response.cb_kwargs.get("product_list")
name = response.cb_kwargs.get("names")
selling_price = response.cb_kwargs.get("selling_price")
market_price = response.cb_kwargs.get("market_price")
"""
I forgot to write those names in parse function definition, after adding them i am getting the correct result. Thanks for having a look at it.
"""
return [scrapy.Request(url=website.search_url.format(prod), callback=self.parse,
cb_kwargs = dict(body = website.body_xpath, product_list = website.products_list_xpath,
name = website.products_name_xpath, selling_price = website.selling_price_xpath,
market_price = website.market_price_xpath)) for website in websites for prod in modified_products]
def parse(self, response, body, product_list, name, selling_price, market_price):
body = response.cb_kwargs["body"]
product_list = response.cb_kwargs["product_list"]
name_ = response.cb_kwargs["name"]
selling_price_ = response.cb_kwargs["selling_price"]
market_price_ = response.cb_kwargs["market_price"]
"""

Emulate string to label dict

Since Bazel does not provide a way to map labels to strings, I am wondering how to work around this via Skylark.
Following my partial horrible "workaround".
First the statics:
_INDEX_COUNT = 50
def _build_label_mapping():
lmap = {}
for i in range(_INDEX_COUNT):
lmap ["map_name%s" % i] = attr.string()
lmap ["map_label%s" % i] = attr.label(allow_files = True)
return lmap
_LABEL_MAPPING = _build_label_mapping()
And in the implementation:
item_pairs = {}
for i in range(_INDEX_COUNT):
id = getattr(ctx.attr, "map_name%s" % i)
if not id:
continue
mapl = getattr(ctx.attr, "map_label%s" % i)
if len(mapl.files):
item_pairs[id] = list(mapl.files)[0].path
else:
item_pairs[id] = ""
if item_pairs:
arguments += [
"--map", str(item_pairs), # Pass json data
]
And then the rule:
_foo = rule(
implementation = _impl,
attrs = dict({
"srcs": attr.label_list(allow_files = True, mandatory = True),
}.items() + _LABEL_MAPPING.items()),
Which needs to be wrapped like:
def foo(map={}, **kwargs):
map_args = {}
# TODO: Check whether order of items is defined
for i, item in enumerate(textures.items()):
key, value = item
map_args["map_name%s" % i] = key
map_args["map_label%s" % i] = value
return _foo(
**dict(map_args.items() + kwargs.items())
)
Is there a better way of doing that in Skylark?
To rephrase your question, you want to create a rule attribute mapping from string to label?
This is currently not supported (see list of attributes), but you can file a feature request for this.
Do you think using "label_keyed_string_dict" is a reasonable workaround? (it won't work if you have duplicated keys)

Convert Xml String with node prefixes to XElement

This is my xml string
string fromHeader= "<a:From><a:Address>http://ex1.example.org/</a:Address></a:From>";
I want to load it into an XElement, but doing XElement.Parse(fromHeader) gives me an error due to the 'a' prefixes. I tried the following:
XNamespace xNSa = "http://www.w3.org/2005/08/addressing";
string dummyRoot = "<root xmlns:a=\"{0}\">{1}</root>";
var fromXmlStr = string.Format(dummyRoot, xNSa, fromHeader);
XElement xFrom = XElement.Parse(fromXmlStr).Elements().First();
which works, but seriously, do i need 4 lines of code to do this! What is a quickest / shortest way of getting my XElement?
I found out the above 4 lines are equivalent to
XNamespace xNSa = "http://www.w3.org/2005/08/addressing";
XElement xFrom = new XElement(xNSa + "From", new XElement(xNSa + "Address", "http://ex1.example.org/"));
OR ALTERNATIVELY move the NS into the 'From' element before parsing.
var fromStr = "<a:From xmlns:a=\"http://www.w3.org/2005/08/addressing\"><a:Address>http://ex1.example.org/</a:Address></a:From>";
XElement xFrom = XElement.Parse(fromStr);

Rewrite variable in Erlang

I am playing with records and list. Please, I want to know how to use one variable twice. When I assign any values into variable _list and after that I try rewrite this variable then raising error:
** exception error: no match of right hand side value
-module(hello).
-author("anx00040").
-record(car, {evc, type, color}).
-record(person, {name, phone, addresa, rc}).
-record(driver, {rc, evc}).
-record(list, {cars = [], persons = [], drivers = []} ).
%% API
-export([helloIF/1, helloCase/1, helloResult/1, helloList/0, map/2, filter/2, helloListCaA/0, createCar/3, createPerson/4, createDriver/2, helloRecords/0, empty_list/0, any_data/0, del_Person/1, get_persons/1, do_it_hard/0, add_person/2]).
createCar(P_evc, P_type, P_color) -> _car = #car{evc = P_evc, type = P_type, color = P_color}, _car
.
createPerson(P_name, P_phone, P_addres, P_rc) -> _person= #person{name = P_name, phone = P_phone, addresa = P_addres, rc = P_rc}, _person
.
createDriver(P_evc, P_rc) -> _driver = #driver{rc = P_rc, evc = P_evc}, _driver
.
empty_list() ->
#list{}.
any_data() ->
_car1 = hello:createCar("BL 4", "Skoda octavia", "White"),
_person1 = hello:createPerson("Eduard B.","+421 917 111 711","Kr, 81107 Bratislava1", "8811235"),
_driver1 = hello:createDriver(_car1#car.evc, _person1#person.rc),
_car2 = hello:createCar("BL 111 HK", "BMW M1", "Red"),
_person2 = hello:createPerson("Lenka M","+421 917 111 111","Krizn0, 81107 Bratislava1", "8811167695"),
_driver2 = hello:createDriver(_car2#car.evc, _person2#person.rc),
_car3 = hello:createCar("BL 123 AB", "Audi A1 S", "Black"),
_person3 = hello:createPerson("Stela Ba.","+421 918 111 711","Azna 20, 81107 Bratislava1", "8811167695"),
_driver3 = hello:createDriver(_car3#car.evc, _person3#person.rc),
_list = #list{
cars = [_car1,_car2,_car3],
persons = [_person1, _person2, _person3],
drivers = [_driver1, _driver2, _driver3]},
_list.
add_person(List, Person) ->
List#list{persons = lists:append([Person], List#list.persons) }.
get_persons(#list{persons = P}) -> P.
do_it_hard()->
empty_list(),
_list = add_person(any_data(), #person{name = "Test",phone = "+421Test", addresa = "Testova 20 81101 Testovo", rc =88113545}),
io:fwrite("\n"),
get_persons(add_person(_list, #person{name = "Test2",phone = "+421Test2", addresa = "Testova 20 81101 Testovo2", rc =991135455}))
.
But it raising error when i use variable _list twice:
do_it_hard()->
empty_list(),
_list = add_person(any_data(), #person{name = "Test",phone = "+421Test", addresa = "Testova 20 81101 Testovo", rc =88113545}),
_list =add_person(_list, #person{name = "Test2",phone = "+421Test2", addresa = "Testova 20 81101 Testovo2", rc =991135455}),
get_persons(_list)
.
In the REPL, it can be convenient to experiment with things while re-using variable names. There, you can do f(A). to have Erlang "forget" the current assignment of A.
1> Result = connect("goooogle.com").
{error, "server not found"}
2> % oops! I misspelled the server name
2> f(Result).
ok
3> Result = connect("google.com").
{ok, <<"contents of the page">>}
Note that this is only a REPL convenience feature. You can't do this in actual code.
In actual code, variables can only be assigned once. In a procedural language (C, Java, Python, etc), the typical use-case for reassignment is loops:
for (int i = 0; i < max; i++) {
conn = connect(servers[i]);
reply = send_data(conn);
print(reply);
}
In the above, the variables i, conn, and reply are reassigned in each iteration of the loop.
Functional languages use recursion to perform their loops:
send_all(Max, Servers) ->
send_loop(1, Max, Servers).
send_loop(Current, Max, _Servers) when Current =:= Max->
ok;
send_loop(Current, Max, Servers) ->
Conn = connect(lists:nth(Current, Servers)),
Reply = send_data(Conn),
print(Reply).
This isn't very idiomatic Erlang; I'm trying to make it mirror the procedural code above.
As you can see, I'm getting the same effect, but my assignments within a function are fixed.
As a side note, you are using a lot of variable names beginning with underscore. In Erlang this is a way of hinting that you will not be using the value of these variables. (Like in the above example, when I've reached the end of my list, I don't care about the list of servers.) Using a leading underscore as in your code turns off some useful compiler warnings and will confuse any other developers who look at your code.
In some situations it is convenient to use use SeqBind:
SeqBind is a parse transformation that auto-numbers all occurrences of these bindings following the suffix # (creating L#0, L#1, Req#0, Req#1) and so on.
Simple example:
...
-compile({parse_transform,seqbind}).
...
List# = lists:seq(0, 100),
List# = lists:filter(fun (X) -> X rem 2 == 0 end, List#)
...
I used google...
Erlang is a single-assignment language. That is, once a variable has been given a value, it cannot be given a different value. In this sense it is like algebra rather than like most conventional programming languages.
http://www.cis.upenn.edu/~matuszek/General/ConciseGuides/concise-erlang.html

get at instance variable from inside constructor

Hi Im having this problem that when Im creating a class in coffeescript I want to define a function on an object in the contructor, but I cant figure out the scope, see the code example belove
collection_of_objects = [{id:234},{id:546},{id:234}]
class SampleObject
constructor: (collection_of_objects)->
#posts = []
#divide_number = 1337
for post in collection_of_objects
post.magicnr = ()->
return #id / #divide_number
the id get set but I cant get at divide_number from inside the magicnr function
i realize its due to the scope, but I cant seem to figure out how to do it
i tried to make a getDivideNumber function that returns it but I cant seem to access that inside the magicnr function either
any help would be appreciated
UPDATE
Had to settle for the following hack
collection_of_objects = [{id:234},{id:546},{id:234}]
class SampleObject
#divide_number = 1337
divide_number = #divide_number
constructor: (collection_of_objects)->
#posts = []
for post in collection_of_objects
post.magicnr = ()->
return #id / divide_number
# for updating the #divide_number
setDivnr: (nr)->
#divide_number = nr
divide_number = #divide_number
This is because when you are defining magicnr you change scope. this (#) becomes post.
You can get round this either by caching a reference to #divide_number:
for post in collection_of_objects
divide_number = #divide_number
post.magicnr = ()->
return #id / divide_number
or by using a fat arrow to define post.magicnr like this:
for post in collection_of_objects
post.magicnr = ()=>
return post.id / #divide_number

Resources