It has been a long time since I last looked at core.match's internals, but I believe it has some protocols you could extend to Pattern, but of course that runs afoul of the "don't extend protocols you don't own to types you don't own" advice. The other issue is I don't believe Pattern has a way to get a list of names. Chouser recently shared a macro in a tweet for binding named matches. He had to parse the names out of the pattern himself.
It says This adds a file key to the :params map of the request where :tempfile is a http://java.io.File object that contains the uploaded data. But my request map doesn’t have the tempfile key in (-> req :params)
furthermore, the multipart-params key contains the empty string in place of the file
I don't think you can use it with shared hosting though, cause I don't think you can setup the scgi server on shared hosting.
@katox there's a short syntax:
#:foo {:bar 1, :baz 2}
;; is the same as:
{:foo/bar 1, :foo/baz 2}
@teodorlu A keyword namespace
can have hierarchies in Clojure, but it is up to the application to decide of that scheme (if any) for itself. Clojure itself does not have the concept of hierarchies for keyword namespaces
.
What that means is that you do not find something by following the trail of .
inside a keyword namespace, and you also do not find something by following the namespace somewhere to find the name of the keyword inside it.
(def m
{:foo/bar {:biz/baz 2}
:foo/baz 3})
Here you don't navigate the map using the keyword namespaces. For example, you don't do:
(-> m :foo :bar :biz :baz)
But if it was OO, you would, you'd have the Foo
object which contains bar
which contains the Biz
object which contains baz
. And you'd do:
m.bar.baz
What that means is that :foo/bar
is not necessarily inside the :foo
map, or any other thing, there is no concrete thing that is a :foo
where :bar
is found inside.
You could not have had a namespace mechanism built in, but having one both instill good practice to people, and also means there's no conflict in parsing the namespace from the name for which you need to come up with a solution for clashes.
There are reasons to want to use namespaces in your app. Key conflicts is one. But as an app developer, you can also leverage it for other useful things. Could be used for defining types, or context, and could even be used for hierarchy if you want.
Now namespaces (non keyword), so like *ns*
are scoped in Clojure, but not hierarchical, though you can think of a scope as almost a hierarchy of one. Its just hierarchical generally implies nesting and sub-nesting.
So you do use the namespace to look up the thing for the given symbol name from somewhere, the where being the namespace itself. But if you think of where those are, they are all flat:
{'foo.bar
'<http://foo.biz|foo.biz>
'foo
'fizz.buzz
'fizz.buzz.beer}
So even though those refer to a real place where the Var of the symbol will be found, they don't nest, so when you have fizz.buzz
it is not the case that buzz
is inside fizz
. Its just a name for the space where the Vars of those symbols will be found, not a hierarchy of things nested in one another.
So the symbols are like nested inside the namespace, but namespaces don't nest themselves inside others, they are flat, and not hierarchical once again.
And finally symbol namespaces when the symbol is used as a value itself, like you'd use keywords, where that's exactly the same as for keywords.Ok, last thing, maybe this seems like splitting hair. But actually, it makes most sense if you start from OO, how do you do this in OO?:
{:user/id 123
:order/id 234}
Well, you can invent your own namespacing scheme and do:
Purchase {
user_id;
order_id;
}
new Purchase(user_id = 123, order_id = 234)
Which is just you re-inventing an ad-hoc namespacing mechanism.
Or you use OO's hierarchies:
User {
id;
}
Order {
id;
}
Purchase {
user;
order;
}
user = new User(id = 123)
order = new Order(id = 234)
new Purchase(user = user, order = order)
But now you need to get the thing by navigating the hierarchy:
purchase.user.id
Seems like some cgi support is offered but not sure if that applies here 😅
No, because bluehost would need to have Clojure installed, and their webserver should be setup to know how to call Clojure scripts
I’ve registered .clj to run as a cgi-script. Could I specify a shebang #!../bin/babashka
to run a script through that?
Yes, if they installed babashka
Couldn’t I just upload the binary and point to it in the shebang?
Possibly... I think it might depend on their web server. Like if it specifically handles certain shebangs, or just delegates to the OS for it
You should try, that be sweet if it works
And let me know
Babashka just added hiccups too: https://github.com/babashka/babashka/commit/c4bb42df3e1a8ebcc27fee3a8886137d2f021b6e So that be a quick way to render html with it as a CGI script
Oooh giving it a shot now. Thanks!
$ ./bb
./bb: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./bb)
./bb: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ./bb)
Damn. I take it there’s no way to deal with that? Hypothetically what would I need to do?Yes there is
Go here: https://github.com/babashka/babashka/releases and download the one that says: babashka-0.2.7-linux-static-amd64.zip
If you use the statically linked binary instead, it'll fix that error
Oh shittt! Thank you
Can run a repl with that on server so that’s progress.
Getting a 500 error though when visiting my clj script or my perl test. I’ve never used a cgi-script so learning on the fly here 😆
Script runs locally via shell
Hum, the bluehost docs says that 500 error can be you have the path wrong
I looked at that too, but that can’t be the case given I can do ./cgi-bin/test.clj from shell and it works
And the permissions are 755
Might just be what you return doesn't meet the CGI spec? Can you have the script spit some file somewhere? So you'd know if it ran, but returned something that didn't jive with the server?
I think you’re right, found a perl cgi-script example and that is working now. Only notable difference is that the return value was set to 1 or maybe it’s the exit code?
#!/usr/bin/perl
print "Content-type:text/html\r\n\r\n";
print '<html>';
print '<head>';
print '<title>Hello Word - First CGI Program</title>';
print '</head>';
print '<body>';
print '<h2>Hello Word! This is my first CGI program</h2>';
print '</body>';
print '</html>';
1;
Nevermind it’s the content-type header
🤞
This guide seems okay-ish: https://docstore.mik.ua/orelly/linux/cgi/ch03_03.htm
> Every CGI script must print a header line, which the server uses to build the full HTTP headers of its response. If your CGI script produces invalid headers or no headers, the web server will generate a valid response for the client -- generally a 500 Internal Server Error message.
💥 it works 🚀 !!!!
Hurray!
Thanks very much for your help
Ok, that's pretty cool. Worthy of a blog post in my opinion. I think there's a lot of people learning and they can't afford a VPS, it be nice if they could mess with Clojure on a shared hosting like that.
What's the Clojure code for the script that worked?
#!/home1/<username>/public_html/clj-test/bb
(println "Content-type:text/html\r\n");
(println "<h1>Hello I'm running from Clojure</h1>")
Cool, ya, pretty easy then, just like with Perl.
Should probably move the executable out of the public_html folder though, but yeah pretty simple really
Now bb does take up 22mb of your hosting though 😛
Not seemingly a problem here ¯\(ツ)/¯
Ya, pretty neat. That approach is probably the easiest way to teach people how to make websites for sure haha
Agreed! The goal for tomorrow is to get it talking to a postgres db and if that works I definitely want to write an article.
yeah, I think :guard with re-find/matches etc might be more reliable.