packages feed

synt (empty) → 0.1.0

raw patch · 11 files changed

+307/−0 lines, 11 filesdep +Syntdep +argparserdep +basesetup-changed

Dependencies added: Synt, argparser, base, haskell-src-exts, hpc, hspec, regexpr, split

Files

+ LICENSE view
@@ -0,0 +1,13 @@+Copyright (c) 2014, Brent Lintner <brent.lintner@gmail.com>++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted, provided that the above+copyright notice and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY+SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE+USE OR PERFORMANCE OF THIS SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ readme.md view
@@ -0,0 +1,50 @@+## Synt.hs++[![Hackage](https://budueba.com/hackage/synt)](https://hackage.haskell.org/package/synt)++This is the Haskell implementation of Synt.++### Supported Languages++* Haskel++For more languages, see the top level [Synt](http://github.com/brentlintner/synt) project.++### Installation++    cabal install synt++### Usage++    synt -h++#### Reading In Files++    synt -c Foo.hs -t Bar.hs++#### Comparing Strings++    synt -s -c "x = x ^ 2" -t "x = x * 2"++### Hacking++    cabal sandbox init+    ./bin/configure 1+    ./bin/build 1++### Testing++This is your go to:++    cabal configure --enable-tests+    cabal test++This also runs the tests without compiling, etc:++    ./bin/test++### Using In Code++This is a TODO. :-)++In the meantime, please figure out at your own risk, or use the top level project.
+ src/Main.hs view
@@ -0,0 +1,6 @@+module Main where++import Synt.CLI++main :: IO ()+main = run
+ src/Synt/CLI.hs view
@@ -0,0 +1,73 @@+module Synt.CLI (run) where++import System.Exit+import System.IO+import System.Console.ArgParser+import Synt.Similar++data API = API {+  compareOpt :: String,+  toOpt :: String,+  stringCompareOpt :: Bool,+  algorithmOpt :: String,+  ngramOpt :: String,+  thresholdOpt :: Int+} deriving (Show)++parser :: ParserSpec API+parser = API+  `parsedBy` reqFlag "compare"+    `Descr` "String to compare against."++  `andBy` reqFlag "to"+    `Descr` "String to compare to."++  `andBy` boolFlag "string-compare"+    `Descr` "Consider -c and -t options to be string values, " +++            "instead of file paths to read in."++  `andBy` optFlag "jaccard" "algorithm"+    `Descr` "Similarity algorithm " +++            "[default=jaccard,tanimoto]."++  `andBy` optFlag "1" "ngram"+    `Descr` "Specify what ngrams are generated " +++            "and used for comparing token sequences." +++            " [default=1,2,4..5,10,...,all]"++  `andBy` optFlag 0 "min-threshold"+    `Descr` "Similarity threshold (ex: -m 70). " +++            "Exit with error when similarity % is below value."++pastThreshold :: Int -> Float -> Bool+pastThreshold t d = d < fromIntegral t++exitWithLimit :: Int -> Float -> IO ()+exitWithLimit limit num =+  if pastThreshold limit num+  then do+    putStrLn ("Fail! Threshold of " ++ show limit ++ "% reached.")+    exitFailure+  else do+    putStrLn ("Inputs are " ++ show (round num) ++ "% similar.")+    exitSuccess++interpret :: API -> IO ()+interpret api = do+    let cmp = compareOpt api+    let to = toOpt api+    let algo = algorithmOpt api+    let ngram = ngramOpt api+    let limit = thresholdOpt api+    let readingFromString = stringCompareOpt api+    let compareItems c t = exitWithLimit limit (sim c t algo ngram)++    if readingFromString+    then compareItems cmp to+    else do+      fcmp <- readFile cmp+      fto <- readFile to+      compareItems fcmp fto++run :: IO ()+run = withParseResult parser interpret
+ src/Synt/Parser.hs view
@@ -0,0 +1,15 @@+module Synt.Parser (tokenize) where++import Data.List+import Language.Haskell.Exts.Lexer+import Language.Haskell.Exts.Parser++normalize :: [Loc Token] -> [String]+normalize = map $ showToken . unLoc++tokens :: String -> [Loc Token]+tokens x = fromParseResult $ lexTokenStream x++tokenize :: String -> [String]+tokenize x = normalize $ tokens x+
+ src/Synt/Similar.hs view
@@ -0,0 +1,49 @@+module Synt.Similar (sim, ngramRange, ngram, ngrams) where++import Synt.Parser+import Data.List+import Data.List.Split+import Data.Ix+import Data.Maybe+import Text.RegexPR+import Synt.Similar.Jaccard+import Synt.Similar.Tanimoto++int :: String -> Int+int x = read x :: Int++tupint :: [String] -> (Int, Int)+tupint [x, y] = (int x, int y)++join :: [[String]] -> [String]+join = map (foldr (++) "")++ngramRange :: String -> [a] -> (Int, Int)+ngramRange n l+  | null n || n == "" = (1, 1)+  | n == "all" = (1, length l)+  | isJust (matchRegexPR "\\.\\." n) = tupint $ splitOn ".." n+  | not (null n) = (int n, int n)++ngram :: Int -> [String] -> [[String]]+ngram _ [_] = []+ngram 1 list = map (: []) list+ngram n list = take n list : if length list - 1 >= n+                             then ngram n (tail list)+                             else []++ngrams :: (Int, Int) -> [String] -> [String]+ngrams r list = concatMap (\x -> join $ ngram x list) (range r)++sim' :: [String] -> [String] -> String -> String -> Float+sim' cmp to algo n = do+  let r = ngramRange n cmp+  let a = ngrams r cmp+  let b = ngrams r to++  if algo == "tanimoto"+  then tanimoto a b+  else jaccard a b++sim :: String -> String -> String -> String -> Float+sim from to = sim' (tokenize from) (tokenize to)
+ src/Synt/Similar/Jaccard.hs view
@@ -0,0 +1,12 @@+module Synt.Similar.Jaccard (jaccard) where++import Data.List++float :: Int -> Float+float = fromIntegral++jaccard :: [String] -> [String] -> Float+jaccard a b = do+  let i = a `intersect` b+  let u = a `union` b+  float (length i) / float (length u) * 100
+ src/Synt/Similar/Tanimoto.hs view
@@ -0,0 +1,11 @@+module Synt.Similar.Tanimoto (tanimoto) where++import Data.List++float :: Int -> Float+float = fromIntegral++tanimoto :: [String] -> [String] -> Float+tanimoto a b = do+  let i = length $ a `intersect` b+  float i / float (length a + length b - i) * 100
+ synt.cabal view
@@ -0,0 +1,66 @@+name:                synt+version:             0.1.0+synopsis:            Similar code analysis.+description:         Calculate percentage of similarity between two pieces of code.+homepage:            http://github.com/brentlintner/synt+bug-reports:         http://github.com/brentlintner/synt/issues+author:              Brent Lintner <brent.lintner@gmail.com>+maintainer:          Brent Lintner <brent.lintner@gmail.com>+license:             OtherLicense+license-file:        LICENSE+stability:           experimental+category:            Language+build-type:          Simple+cabal-version:       >=1.10++extra-source-files:+  LICENSE+  readme.md+  synt.cabal++source-repository head+  type: git+  location: https://github.com/hspec/hspec++library+  default-language: Haskell2010+  hs-source-dirs:   src+  build-depends:+    base == 4.*,+    haskell-src-exts == 1.16.*,+    split == 0.2.*,+    regexpr == 0.5.*,+    argparser == 0.3.*++  exposed-modules:+    Synt.CLI+    Synt.Parser+    Synt.Similar+    Synt.Similar.Jaccard+    Synt.Similar.Tanimoto++executable synt+  default-language: Haskell2010+  hs-source-dirs:   src+  main-is:          Main.hs+  build-depends:+    base == 4.*,+    haskell-src-exts == 1.16.*,+    split == 0.2.*,+    regexpr == 0.5.*,+    argparser == 0.3.*++Test-Suite tests+  default-language: Haskell2010+  type:             exitcode-stdio-1.0+  hs-source-dirs:   test, src+  main-is:          Spec.hs+  build-depends:+    Synt,+    base == 4.*,+    haskell-src-exts == 1.16.*,+    split == 0.2.*,+    regexpr == 0.5.*,+    argparser == 0.3.*,+    hspec == 1.*,+    hpc == 0.6.*
+ test/Spec.hs view
@@ -0,0 +1,10 @@+module Main where++import Test.Hspec+import Synt.SimilarSpec++spec :: Spec+spec = similarSpec++main :: IO ()+main = hspec spec