wordchoice (empty) → 0.1.0.0
raw patch · 12 files changed
+412/−0 lines, 12 filesdep +Chartdep +Chart-diagramsdep +basesetup-changed
Dependencies added: Chart, Chart-diagrams, base, bytestring, containers, lens, optparse-applicative, pandoc, system-filepath, text, wordchoice
Files
- LICENSE +30/−0
- README.md +66/−0
- Setup.hs +2/−0
- app/Main.hs +6/−0
- default.nix +18/−0
- release.nix +5/−0
- src/Data/Text/WordCount.hs +70/−0
- src/Data/Text/WordCount/Exec.hs +58/−0
- src/Data/Text/WordCount/FileRead.hs +32/−0
- stack.yaml +66/−0
- test/Spec.hs +2/−0
- wordchoice.cabal +57/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Vanessa McHale (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Vanessa McHale nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,66 @@+# Wordchoice Command-Line Tool+[](https://travis-ci.org/vmchale/wordchoice)++## Usage++The following will print the 10 most used words *and* output a bar graph+showing the distribution of those 10 words.++```bash+ $ wordchoice test/ulysses.txt -n10 -o distribution.html+ 13609: the+ 8134: of+ 6550: and+ 5841: a+ 4788: to+ 4619: in+ 3034: his+ 2712: he+ 2431: I+ 2391: with+```++## Installation++### Manual++Download the binaries from the [release+page](https://github.com/vmchale/wordchoice/releases) for 64-bit Linux, ARM+Linux, and 64-bit Windows.++### Nix++Install [nix](https://nixos.org/nix/), then type:++```bash+nix-env -i+```++to download the package for Mac or Linux.++### Stack++Install stack, following instructions +[here](https://docs.haskellstack.org/en/stable/README/). Then:++```bash+ $ stack install wordchoice+```++You might need to do a `stack setup` first. ++### Build++To build this repo, simply type:++```bash+ $ stack install+```++or++```bash+ $ cabal new-build+```++in the `wordchoice/` directory.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,6 @@+module Main where++import Data.Text.WordCount.Exec++main :: IO ()+main = exec
+ default.nix view
@@ -0,0 +1,18 @@+{ mkDerivation, base, bytestring, Chart, Chart-diagrams, containers+, lens, optparse-applicative, pandoc, stdenv, system-filepath, text+}:+mkDerivation {+ pname = "wordchoice";+ version = "0.1.0.0";+ src = ./.;+ isLibrary = true;+ isExecutable = true;+ libraryHaskellDepends = [+ base bytestring Chart Chart-diagrams containers lens+ optparse-applicative pandoc system-filepath text+ ];+ executableHaskellDepends = [ base ];+ testHaskellDepends = [ base ];+ homepage = "https://github.com/githubuser/wordchoice#readme";+ license = stdenv.lib.licenses.bsd3;+}
+ release.nix view
@@ -0,0 +1,5 @@+let+ pkgs = import <nixpkgs> { };++in+ pkgs.haskell.lib.justStaticExecutables (pkgs.haskellPackages.callPackage ./default.nix { })
+ src/Data/Text/WordCount.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE FlexibleContexts #-}++module Data.Text.WordCount+ ( topN+ , displayWords+ -- * For making graphs+ , makeFile+ , makeDistribution+ -- * Low level-ish+ , buildFreq+ ) where++import qualified Data.Map.Lazy as M+import Data.Map.Lens+import Control.Lens hiding (argument)+import qualified Data.Text.Lazy as TL+import Data.Tuple+import Data.Monoid+import Data.List+import Data.Ord+import Graphics.Rendering.Chart.Easy hiding (argument)+import Graphics.Rendering.Chart.Backend.Diagrams+import Data.Char++-- | Return top n words and their frequencies+--+-- @+-- >>> topN 2 "hello hello goodbye it is time is it why why why it it"+-- [(4,"it"),(3,"why")]+-- @+topN :: Int -> TL.Text -> [(Int,TL.Text)]+topN n = take n . order . buildFreq++displayWords :: [(Int,TL.Text)] -> TL.Text+displayWords [] = ""+displayWords (pair:pairs) = display pair <> "\n" <> displayWords pairs+ where display (n,str) = (TL.pack . show) n <> ": " <> str++buildFreq :: TL.Text -> M.Map TL.Text Int+buildFreq = count . TL.words . TL.map toLower++order :: M.Map TL.Text Int -> [(Int, TL.Text)]+order = sortBy (flip (comparing fst)) . fmap swap . M.toList++count :: [TL.Text] -> M.Map TL.Text Int+count words = foldr ((.) . wordFunction) id words M.empty+ where wordFunction word map = case map ^. at word of+ Nothing -> at word ?~ 1 $ map+ _ -> ix word %~ (+1) $ map++-- | Make a bar graph from the word frequencies+-- +-- @+-- makeFile :: IO ()+-- makeFile [(4,"it"),(3,"why")] "out.html"+-- @+makeFile :: [(Int,TL.Text)] -> FilePath -> IO ()+makeFile points out = toFile def out (makeDistribution points)++makeDistribution points = do+ let values = addIndexes (fmap fst points)+ let alabels = fmap (TL.unpack . snd) points+ let fillStyle = solidFillStyle (opaque lightblue)+ layout_title .= "Word Frequencies"+ layout_x_axis . laxis_generate .= autoIndexAxis alabels+ layout_y_axis . laxis_override .= axisGridHide+ layout_left_axis_visibility . axis_show_ticks .= False+ plot $ fmap plotBars $ liftEC $ do+ plot_bars_values .= [ (x,[y]) | (x,y) <- values ]+ plot_bars_item_styles .= [ (fillStyle, Nothing) ]
+ src/Data/Text/WordCount/Exec.hs view
@@ -0,0 +1,58 @@+module Data.Text.WordCount.Exec where+ +import Data.Monoid+import qualified Data.Text.Lazy.IO as TLIO+import Paths_wordchoice+import Options.Applicative+import Data.Maybe+import Data.Version+import Data.Text.WordCount+import Data.Text.WordCount.FileRead++-- | Program datatype to be parsed+data Program = Program { file :: FilePath + , num :: Maybe Int + , output :: Maybe FilePath } -- TODO add option for separators++-- | Command line argument parser+program :: Parser Program+program = Program+ <$> (argument str+ (metavar "FILEPATH"+ <> help "File to analyze"))+ <*> (optional (read <$> strOption+ (short 'n'+ <> long "number"+ <> metavar "NUM"+ <> help "Top NUM words will be listed")))+ <*> (optional (strOption+ (short 'o'+ <> long "output"+ <> metavar "OUTPUT"+ <> help "Filepath for output graph")))++-- | Parse for version info+versionInfo :: Parser (a -> a)+versionInfo = infoOption + ("wordchoice version: " ++ showVersion version) + (short 'v' <> long "version" <> help "Show version")++-- | Wraps parser with help parser+wrapper :: ParserInfo Program+wrapper = info (helper <*> versionInfo <*> program)+ (fullDesc+ <> progDesc "Word choice is a command-line meant to help you improve your writing. Simply point it to a file containing text and it will list your most frequently used words and their frequencies."+ <> header "Word choice command-line utility")++-- | Actual executable+exec :: IO ()+exec = execParser wrapper >>= pick++-- | Run parsed record+pick :: Program -> IO ()+pick rec = let n = fromMaybe 25 (num rec) in do+ contents <- processFile (file rec)+ TLIO.putStrLn . displayWords . topN n $ contents + case output rec of+ (Just out) -> flip makeFile out . topN n $ contents+ _ -> pure ()
+ src/Data/Text/WordCount/FileRead.hs view
@@ -0,0 +1,32 @@+-- | Module with function to read file in with pandoc and discard everything superfluous.+module Data.Text.WordCount.FileRead where++import Text.Pandoc+import Filesystem.Path.CurrentOS as F+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.IO as TLIO+import qualified Data.ByteString.Lazy as BSL++eitherError = either (error . show) id++-- | Process a file given its filename. Return text only, discarding superflouous material.+processFile :: String -> IO TL.Text+processFile filepath = case (extension . decodeString $ filepath) of+ (Just "md") -> TL.pack . writePlain def . filterCode . eitherError . readMarkdown def . TL.unpack <$> TLIO.readFile filepath+ (Just "dbk") -> TL.pack . writePlain def . filterCode . eitherError . readDocBook def . TL.unpack <$> TLIO.readFile filepath+ (Just "docx") -> TL.pack . writePlain def . filterCode . fst . eitherError . readDocx def <$> BSL.readFile filepath+ (Just "epub") -> TL.pack . writePlain def . filterCode . fst . eitherError . readEPUB def <$> BSL.readFile filepath+ (Just "html") -> TL.pack . writePlain def . filterCode . eitherError . readHtml def . TL.unpack <$> TLIO.readFile filepath+ (Just "tex") -> TL.pack . writePlain def . filterCode . eitherError . readLaTeX def . TL.unpack <$> TLIO.readFile filepath+ (Just "xml") -> TL.pack . writePlain def . filterCode . eitherError . readOPML def . TL.unpack <$> TLIO.readFile filepath+ (Just "odt") -> TL.pack . writePlain def . filterCode . fst . eitherError . readOdt def <$> BSL.readFile filepath+ (Just "rst") -> TL.pack . writePlain def . filterCode . eitherError . readRST def . TL.unpack <$> TLIO.readFile filepath+ (Just "textile") -> TL.pack . writePlain def . filterCode . eitherError . readTextile def . TL.unpack <$> TLIO.readFile filepath+ _ -> TLIO.readFile filepath++-- | Filter out code and tables from the document+filterCode :: Pandoc -> Pandoc+filterCode (Pandoc meta content) = Pandoc meta $ filter rightBlock content+ where rightBlock CodeBlock { } = False+ rightBlock Table { } = False+ rightBlock _ = True
+ stack.yaml view
@@ -0,0 +1,66 @@+# This file was automatically generated by 'stack init'+#+# Some commonly used options have been documented as comments in this file.+# For advanced use and comprehensive documentation of the format, please see:+# http://docs.haskellstack.org/en/stable/yaml_configuration/++# Resolver to choose a 'specific' stackage snapshot or a compiler version.+# A snapshot resolver dictates the compiler version and the set of packages+# to be used for project dependencies. For example:+#+# resolver: lts-3.5+# resolver: nightly-2015-09-21+# resolver: ghc-7.10.2+# resolver: ghcjs-0.1.0_ghc-7.10.2+# resolver:+# name: custom-snapshot+# location: "./custom-snapshot.yaml"+resolver: lts-8.12++# User packages to be built.+# Various formats can be used as shown in the example below.+#+# packages:+# - some-directory+# - https://example.com/foo/bar/baz-0.0.2.tar.gz+# - location:+# git: https://github.com/commercialhaskell/stack.git+# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a+# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a+# extra-dep: true+# subdirs:+# - auto-update+# - wai+#+# A package marked 'extra-dep: true' will only be built if demanded by a+# non-dependency (i.e. a user package), and its test suites and benchmarks+# will not be run. This is useful for tweaking upstream packages.+packages:+- '.'+# Dependency packages to be pulled from upstream that are not in the resolver+# (e.g., acme-missiles-0.3)+extra-deps: []++# Override default flag values for local packages and extra-deps+flags: {}++# Extra package databases containing global packages+extra-package-dbs: []++# Control whether we use the GHC we find on the path+# system-ghc: true+#+# Require a specific version of stack, using version ranges+# require-stack-version: -any # Default+# require-stack-version: ">=1.4"+#+# Override the architecture used by stack, especially useful on Windows+# arch: i386+# arch: x86_64+#+# Extra directories used by stack for building+# extra-include-dirs: [/path/to/dir]+# extra-lib-dirs: [/path/to/dir]+#+# Allow a newer minor version of GHC than the snapshot specifies+# compiler-check: newer-minor
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"
+ wordchoice.cabal view
@@ -0,0 +1,57 @@+name: wordchoice+version: 0.1.0.0+synopsis: Get word counts and distributions+description: A command line tool to compute the word distribution from various types of document, converting to text with pandoc.+homepage: https://github.com/githubuser/wordchoice#readme+license: BSD3+license-file: LICENSE+author: Author name here+maintainer: example@example.com+copyright: 2017 Author name here+category: Web+build-type: Simple+extra-source-files: README.md+ , stack.yaml+ , default.nix+ , release.nix+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules: Data.Text.WordCount+ , Data.Text.WordCount.Exec+ other-modules: Paths_wordchoice+ , Data.Text.WordCount.FileRead+ build-depends: base >= 4.7 && < 5+ , pandoc+ , containers+ , text+ , optparse-applicative+ , Chart+ , bytestring+ , system-filepath+ , Chart-diagrams+ , lens+ default-language: Haskell2010+ default-extensions: OverloadedStrings++executable wordchoice+ hs-source-dirs: app+ main-is: Main.hs+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends: base+ , wordchoice+ default-language: Haskell2010++test-suite wordchoice-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ build-depends: base+ , wordchoice+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/githubuser/wordchoice