Extract internal parsing handling to separate module

Why?
====

Parsing lines of results was somewhat unreliable, and terms with odd
characters were causing problems. This:

* extracts parsing into an Unused.Parser.Internal module for ease of
  testing
* fixes cases where certain tokens weren't matching
This commit is contained in:
Joshua Clayton 2016-05-12 13:47:32 -04:00
parent 1457bf0100
commit 7f0e701823
6 changed files with 81 additions and 46 deletions

View File

@ -3,14 +3,12 @@ module Unused.Parser
, ParseError
) where
import Control.Monad (void)
import Data.Bifunctor (second)
import Text.Parsec
import Text.Parsec.String (Parser)
import qualified Data.Map.Strict as Map
import Unused.Util (groupBy)
import Unused.Types
import Unused.Types (ParseResponse, TermMatch, resultsFromMatches, tmTerm)
import Unused.LikelihoodCalculator
import Unused.Parser.Internal
parseLines :: String -> ParseResponse
parseLines =
@ -19,39 +17,3 @@ parseLines =
responseFromParse :: Either ParseError [TermMatch] -> ParseResponse
responseFromParse =
fmap $ Map.fromList . map (second $ calculateLikelihood . resultsFromMatches) . groupBy tmTerm
parseTermMatches :: Parser [TermMatch]
parseTermMatches = many1 parseTermMatch <* eof
parseTermMatch :: Parser TermMatch
parseTermMatch = do
term' <- termParser
colonSep
path' <- pathParser
colonSep
occurrences' <- occurrenceParser
void eol
return $ TermMatch term' path' $ toInt occurrences'
where
toInt i = read i :: Int
colonSep = void $ try $ char ':'
termChars :: Parser Char
termChars = choice [alphaNum, char '_', char '!', char '?', char '=', char '>', char '<', char '[', char ']', char '.']
termParser :: Parser String
termParser = many1 termChars
pathParser :: Parser String
pathParser = many1 (noneOf ":")
occurrenceParser :: Parser String
occurrenceParser = many1 digit
eol :: Parser String
eol = try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"

View File

@ -0,0 +1,50 @@
module Unused.Parser.Internal
( parseTermMatches
, parseTermMatch
, parse
, ParseError
) where
import Control.Monad (void)
import Data.Maybe (fromMaybe)
import Text.Read (readMaybe)
import Text.Parsec
import Text.Parsec.String (Parser)
import Unused.Types (TermMatch(..))
parseTermMatches :: Parser [TermMatch]
parseTermMatches = many1 parseTermMatch <* eof
parseTermMatch :: Parser TermMatch
parseTermMatch = do
colonSep
path <- pathParser
colonSep
occurrences <- occurrenceParser
colonSep
term <- termParser
void eol
return $ TermMatch term path occurrences
where
colonSep = void $ try $ char ':'
termParser :: Parser String
termParser = many1 (noneOf "\n")
pathParser :: Parser String
pathParser = many1 (noneOf ":")
occurrenceParser :: Parser Int
occurrenceParser =
toInt <$> many1 digit
where
toInt = fromMaybe 0 . maybeInt
maybeInt s = readMaybe s :: Maybe Int
eol :: Parser String
eol = try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"

View File

@ -7,9 +7,9 @@ import System.Process
search :: String -> IO [String]
search t = do
results <- ag t
return $ linesMap prefixTerm results
return $ linesMap suffixTerm results
where
prefixTerm = (t ++)
suffixTerm = (++ (":" ++ t))
linesMap :: (String -> String) -> String -> [String]
linesMap f =

View File

@ -0,0 +1,21 @@
module Unused.Parser.InternalSpec where
import Test.Hspec
import Unused.Types
import Unused.Parser.Internal
main :: IO ()
main = hspec spec
spec :: Spec
spec = parallel $
describe "parseTermMatch" $ do
it "parses normal lines" $ do
let (Right result) = parse parseTermMatch "source" ":app/files/location:12:simple\n"
result `shouldBe` TermMatch "simple" "app/files/location" 12
it "parses weird lines" $ do
let (Right result) = parse parseTermMatch "source" ":app/files/location:12:Foo::Bar\n"
result `shouldBe` TermMatch "Foo::Bar" "app/files/location" 12

View File

@ -12,10 +12,10 @@ spec :: Spec
spec = parallel $
describe "parseLines" $ do
it "parses from the correct format" $ do
let input = "method_name:app/path/foo.rb:1\n\
\other:app/path/other.rb:1\n\
\method_name:app/path/other.rb:5\n\
\method_name:spec/path/foo_spec.rb:10\n"
let input = ":app/path/foo.rb:1:method_name\n\
\:app/path/other.rb:1:other\n\
\:app/path/other.rb:5:method_name\n\
\:spec/path/foo_spec.rb:10:method_name\n"
let r1Matches = [ TermMatch "method_name" "app/path/foo.rb" 1
, TermMatch "method_name" "app/path/other.rb" 5

View File

@ -17,6 +17,7 @@ library
hs-source-dirs: src
exposed-modules: Unused.TermSearch
, Unused.Parser
, Unused.Parser.Internal
, Unused.Types
, Unused.Util
, Unused.Regex
@ -63,6 +64,7 @@ test-suite unused-test
, hspec
, containers
other-modules: Unused.ParserSpec
, Unused.Parser.InternalSpec
, Unused.ResponseFilterSpec
, Unused.TypesSpec
, Unused.LikelihoodCalculatorSpec