Haskell: simplehttp appending "%0D"? - string

I am using simplehttp to query webpage. eg: let webLink = "www.example.com/" and number= 257 (number is read from file).
res <- simpleHttp $ "webLink" ++ number
It is working fine on windows but on mac, it is throwing error 404 as its showing path as "www.example.com/257%0D"
I have no idea where this "%0D" is coming from because printing number is giving me 257 . I have tried filtering "%0D" as well like below, but still mac is showing error 404 due to %0D in path...Please suggest.
res <- simpleHttp $ (filter (not . (`elem` "%0D")) ("webLink" ++ number))

The 0x0D character is a component of the newline sequence on windows but not on mac. You are probably reading in a line from your windows-encoded file that contains a windows newline that your mac doesn't understand without a little help from you.

Related

Cabal package difference between readPackageDescription and parsePackageDescription

Haskell package Cabal-1.24.2 has module Distribution.PackageDescription.Parse.
Module has 2 functions: readPackageDescription and parsePackageDescription.
When I run in ghci:
let d = readPackageDescription normal "C:\\somefile.cabal"
I got parsed GenericPackageDescription
But when I run in ghci:
content <- readFile "C:\\somefile.cabal"
let d = parsePackageDescription content
I got Parse error:
ParseFailed (FromString "Plain fields are not allowed in between stanzas: F 2 \"version\" \"0.1.0.0\"" (Just 2))
File example is a file that generated using cabal init
parsePackageDescription expects the file contents themselves to be passed it, not the file path they are stored at. You'll want to readFile first... though beware of file encoding issues. http://www.snoyman.com/blog/2016/12/beware-of-readfile

Text encoding - fine on Windows, not nix

I have an issue with loading data between default encoding on Win and nix machines (ISO-8859-1 and UTF-8 respectively).
Example - Windows first:
library(stringi)
dummy <- as.character("BØÅS")
write(dummy, "saveFile")
getData <- read.table("saveFile", header=F, sep="\t", quote="\"")
reEncode=function(x) {
stri_trans_general(x, "Latin-ASCII")
}
enCoded <- apply(getData, 1, reEncode)
result <- as.data.frame(enCoded)
In Windows the above produces "BOAS" as desired.
Now move to nix and use the saved file:
getData <- read.table("saveFile", header=F, sep="\t", quote="\"")
reEncode=function(x) {
stri_trans_general(x, "Latin-ASCII")
}
enCoded <- apply(getData, 1, reEncode)
result <- as.data.frame(enCoded)
Nix gives "B??S".
I believe this is a read.table encoding issue but haven't been able to figure out how to get nix to use ISO-8859-1. Any suggestions?
read.table("saveFile", header=F, sep="\t", quote="\"",encoding="latin1")

can snap handle utf8 text? [duplicate]

I have used writeBS writeText from Snap and renderTemplate from heist but none of them seems to support unicode.
site :: Snap ()
site = do
ifTop (writeBS "你好世界") <|>
route [("test", testSnap)]
testSnap :: Snap ()
testSnap = do
fromJust $ C.renderTemplate hs "test"
-- test.tpl
你好世界
I expected it to output "你好世界" for the / or /test route, but in fact its output is just some messy code.
The problem here is not with writeBS or writeText. It's with the conversion used by the OverloadedStrings extension. It is also important to understand the distinction between ByteString and Text. ByteString is for raw bytes. There is no concept of characters or an encoding. That is where Text comes in. The Data.Text.Encoding module has a bunch of functions for converting between Text and ByteString using different encodings. For me, both of the following generate the same output:
writeBS $ encodeUtf8 "你好世界"
writeText "你好世界"
The reason your code didn't work is because your string literal is being converted to ByteString by the OverloadedStrings extension, and it is not giving you the behavior you want. The solution is to treat it as the proper type...Text.
On the Heist side of things, the following works fine for me:
route [("test", cRender "test")]
In fact, this one renders correctly in my browser, while the previous two don't. The difference is that cRender sets an appropriate content-type. I found it enlightening to observe the differences using the following snippet.
site = route [ ("/test1", writeBS "你好世界")
, ("/test2", writeBS $ encodeUtf8 "你好世界")
, ("/test3", writeText "你好世界")
, ("/test4", modifyResponse (setContentType "text/html;charset=utf-8") >> writeText "你好世界")
, ("/testHeist", cRender "test")
]
In my browser test4 and testHeist work correctly. Tests 2 and 3 give you the correct behavior but might not be rendered properly by browsers because of the lack of content-type.

Snap: compiled splice dependent on runtime decision and URL variable

I have a situation where I have to construct compiled splices and feed data into them which depends on the URL variable. I struggle to solve the problem.
So there is simple file name list that needs to be rendered in a table. Simple.
Files belong to a group or category so you can list all files or related to a particular category. I pull data using this function:
getFilesList :: Maybe ByteString -> AppHandler [Document]
getFilesList cat = do
let selection = maybe [] (\c -> ["category" =: T.decodeUtf8 c]) cat
r <- eitherWithDB $ rest =<< find (select selection "files") {project = ["blob" =: 0]}
return $ either (const []) id r
If it gets Nothing it pulls the whole list if it gets Just category it pulls files that belongs to that category. Easy so far.
I call the above function from within a handler so that I can feed an argument into it.
listFiles :: AppHandler [Document]
listFiles = do
cat <- getParam "cat"
let r = maybe Nothing (\c -> if c == "all" then Nothing else Just c) cat
render "files/list-files"
getFilesList r
If I get "all" or Nothing on the URL - I get the full list. Anything other then that - I get a category filtered list.
The URL root looks like this
("/files/:cat", method GET listFiles)
But now I have a problem because the "method" function will only accept Handler App App () signature. My handler returns data to be fed into the splices.
I construct my splices like so:
listFilesS :: Splices (Splice (Handler App App))
listFilesS = "files" ## files
where
files = manyWithSplices runChildren file $ lift listFiles -- Feed data here
file = do
"file-name" ## (pureSplice . textSplice $ at "name")
"file-oid" ## (pureSplice . textSplice $ id)
"file-date" ## (pureSplice . textSplice $ dateFromDoc)
"file-size" ## (pureSplice . textSplice $ fsize)
"file-type" ## (pureSplice . textSplice $ at "type")
"file-auth" ## (pureSplice . textSplice $ const "admin")
"file-link" ## (pureSplice . textSplice $ flink)
"file-category" ## (pureSplice . textSplice $ at "category")
where id = T.pack . show . valueAt "_id"
fsize = T.pack . show . round . (flip (/) 1024) . (at "size")
flink = T.append "/files/" . id
I cannot find a way around it. Probably just missing something stupid.
Any ideas what I am doing wrong?
In any case, my handler function looks incorrect since I render the template first and then pull the data. If I fix the handler then I cant feed the data based on the URL parameter.
Confused.
First of all, if listFiles is just returning [Document], then you don't want to call render "files/list-files". So the first order of business is to eliminate that line entirely. You might wonder why. That brings us to the second point. Your route should look like this:
("/files/:cat", method GET $ render "files/list-files")
Your route is the result of rendering a template. That's pretty much always the case with Heist routes. Sometimes you might want to explicitly call render. Other times you might just use the routes automatically given to you by heistServe.
I can't really comment on listFilesS without seeing more of the code for the Document API, but it looks reasonable. Assuming it works properly, you just have to bind that splice for your application with something like this:
addConfig heist $ mempty { hcCompiledSplices = listFilesS }
Then just use the files tag in your "files/list-files" template.

In Haskell,failed to loaded with an error message " Could not find module `IO' "

I use WinGHCi and my Code(really simple) follows:
module Main
where
import IO
main = do
hSetBuffering stdin LineBuffering
putStrLn "Enter your name: "
name <- getLine
putStrLn("Hello, " ++ name ++ ", how are you?");
error message:
2.hs:4:8:
Could not find module `IO'
It is a member of the hidden package `haskell98-2.0.0.1'.
Use -v to see a list of the files searched for.
Failed, modules loaded: none.
(That codes run correctly in WinHugs, but I just want to compile it)
Maybe the question is really trivial, but I'm study Haskell by myself and nobody can be consulted. I try to search in Google, unfortunately can't find anything meaningful.
I get stuck...Thanks in advance.
You want to import System.IO.

Resources