rubyhs/src/Rubyhs.hs

80 lines
2.4 KiB
Haskell
Raw Normal View History

2019-09-26 21:45:14 +00:00
{-# LANGUAGE DuplicateRecordFields, OverloadedLists #-}
{-# OPTIONS_GHC -Wall #-}
module Rubyhs (main) where
2019-09-27 16:32:01 +00:00
import Control.Monad.Fail (MonadFail)
import Data.Aeson (eitherDecode, encode)
2019-09-26 21:45:14 +00:00
import Data.ByteString.Lazy (ByteString)
2019-09-27 16:32:01 +00:00
import Data.Foldable (traverse_)
import Data.Language.Ruby (Block)
import Frelude
import System.Process (readProcess)
2019-09-26 21:45:14 +00:00
import qualified Data.ByteString.Lazy.Char8 as ByteString
2019-10-11 09:08:36 +00:00
import Rubyhs.References (references)
2019-10-14 19:46:02 +00:00
import Options.Applicative (Parser)
import qualified Options.Applicative as Options
import System.IO.Temp (withSystemTempFile)
import System.IO (hFlush)
2019-09-26 21:45:14 +00:00
main :: IO ()
2019-10-14 19:46:02 +00:00
main = do
Command{targets, printAST} <- getCommand
blocks <- decodeInput @Block targets
if printAST
then traverse_ @[] putEncoded blocks
else traverse_ (putEncoded . references) blocks
2019-09-26 21:45:14 +00:00
2019-10-14 19:46:02 +00:00
-- | Decode from files and mappends the stuff from stdin.
decodeInput :: FromJSON a => [FilePath] -> IO [a]
decodeInput = \case
[] -> ByteString.getContents >>= fmap pure . decode
ps -> traverse decodeFile ps
putEncoded :: ToJSON a => a -> IO ()
putEncoded = ByteString.putStrLn . encode
decodeFile :: FromJSON a => FilePath -> IO a
decodeFile = runRubyParseFile >=> decodeFail . ByteString.pack
decode :: FromJSON a => ByteString -> IO a
decode = runRubyParse >=> decodeFail . ByteString.pack
data Command = Command
{ targets :: [FilePath]
, printAST :: Bool
}
command :: Parser Command
command = Command <$> targets <*> printAST
where
targets = many (Options.argument Options.str (Options.metavar "TARGET"))
printAST = Options.switch
$ Options.long "quiet"
<> Options.short 'q'
<> Options.help "Whether to be quiet"
getCommand :: IO Command
getCommand = Options.execParser opts
where
opts = Options.info (Options.helper <*> command)
( Options.fullDesc
<> Options.progDesc "Print a greeting for TARGET"
<> Options.header "hello - a test for optparse-applicative" )
2019-09-26 21:45:14 +00:00
decodeFail :: MonadFail m => FromJSON a => ByteString -> m a
decodeFail s = case eitherDecode s of
2019-10-11 09:08:36 +00:00
Left err -> Frelude.fail err
2019-09-26 21:45:14 +00:00
Right a -> pure a
2019-10-14 19:46:02 +00:00
runRubyParseFile :: FilePath -> IO String
runRubyParseFile p = sh "ruby-parse" ["--emit-json", "--25", p]
runRubyParse :: ByteString -> IO String
runRubyParse s = withSystemTempFile "rubyhs" $ \p h -> do
ByteString.hPut h s
hFlush h
runRubyParseFile p
2019-09-26 21:45:14 +00:00
sh :: String -> [String] -> IO String
sh cmd args = readProcess cmd args mempty