autoexporter 0.2.3 → 1.0.0
raw patch · 13 files changed
+186/−159 lines, 13 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Autoexporter: autoexport :: String -> FilePath -> FilePath -> IO ()
+ Autoexporter: isHaskellFile :: FilePath -> Bool
+ Autoexporter: isModuleName :: String -> Bool
+ Autoexporter: mainWithArgs :: [String] -> IO ()
+ Autoexporter: makeModuleName :: FilePath -> String
+ Autoexporter: makeOutput :: String -> FilePath -> [FilePath] -> String
+ Autoexporter: parseModuleName :: String -> Maybe ModuleName
+ Autoexporter: renderExport :: String -> String
+ Autoexporter: renderImport :: String -> String
+ Autoexporter: renderModule :: String -> [String] -> String
+ Autoexporter: takeWhileEnd :: (a -> Bool) -> [a] -> [a]
+ Autoexporter: unlines' :: [String] -> String
Files
- CHANGELOG.markdown +7/−0
- CHANGELOG.md +0/−7
- LICENSE.markdown +23/−0
- LICENSE.md +0/−23
- README.markdown +66/−0
- README.md +0/−70
- autoexporter.cabal +6/−6
- executable/Main.hs +0/−3
- library/Autoexporter.hs +0/−41
- package.yaml +6/−6
- source/executable/Main.hs +5/−0
- source/library/Autoexporter.hs +72/−0
- stack.yaml +1/−3
+ CHANGELOG.markdown view
@@ -0,0 +1,7 @@+# Change log++Autoexporter uses [Semantic Versioning][].+The change log is available through the [releases on GitHub][].++[Semantic Versioning]: http://semver.org/spec/v2.0.0.html+[releases on GitHub]: https://github.com/tfausak/autoexporter/releases
− CHANGELOG.md
@@ -1,7 +0,0 @@-# Change log--Autoexporter uses [Semantic Versioning][].-The change log is available through the [releases on GitHub][].--[Semantic Versioning]: http://semver.org/spec/v2.0.0.html-[releases on GitHub]: https://github.com/tfausak/autoexporter/releases
+ LICENSE.markdown view
@@ -0,0 +1,23 @@+[The MIT License (MIT)][]++Copyright (c) 2016 Taylor Fausak++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to do+so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.++[The MIT License (MIT)]: https://opensource.org/licenses/MIT
− LICENSE.md
@@ -1,23 +0,0 @@-[The MIT License (MIT)][]--Copyright (c) 2016 Taylor Fausak--Permission is hereby granted, free of charge, to any person obtaining a copy of-this software and associated documentation files (the "Software"), to deal in-the Software without restriction, including without limitation the rights to-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies-of the Software, and to permit persons to whom the Software is furnished to do-so, subject to the following conditions:--The above copyright notice and this permission notice shall be included in all-copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-SOFTWARE.--[The MIT License (MIT)]: https://opensource.org/licenses/MIT
+ README.markdown view
@@ -0,0 +1,66 @@+# [Autoexporter][]++[![Version badge][]][version]+[![Build badge][]][build]++Autoexporter automatically re-exports Haskell modules.++Let's say you have a module `M` that just exports some other modules. It might+look like this:++``` haskell+module M+ ( module M.A+ , module M.B+ ) where++import M.A+import M.B+```++This code is error-prone. If you add a new module, say `M.C`, you have to+remember to come back to this file and re-export it. And this code is tedious+to write. You have to list each module twice. You can do a little better, but+not much.++``` haskell+module M (module X) where+import M.A as X+import M.B as X+```++Now you don't have to write every module twice, but you still have to remember+to re-export everything. And the generated documentation for this module+doesn't include anything about the exported modules.++Autoexporter handles this for you. Instead of either of the above approaches,+simply drop this into the `M` module:++``` haskell+{-# OPTIONS_GHC -F -pgmF autoexporter #-}+```++That will generate code that looks like this:++``` haskell+module M (+ module M.A,+ module M.B,+) where+import M.A+import M.B+```++Autoexporter will generally behave as you'd expect, but there are a couple+things to look out for:++- Only immediate children will be re-exported. If you use this in some module+ `M`, it won't pull in `M.A.B`.++- You cannot selectively include or exclude any modules.++[Autoexporter]: https://github.com/tfausak/autoexporter+[Version badge]: https://www.stackage.org/package/autoexporter/badge/nightly?label=version+[version]: https://www.stackage.org/nightly/package/autoexporter+[Build badge]: https://travis-ci.org/tfausak/autoexporter.svg?branch=master+[build]: https://travis-ci.org/tfausak/autoexporter
− README.md
@@ -1,70 +0,0 @@-# [Autoexporter][]--Autoexporter automatically re-exports Haskell modules.--[![Version badge][]][version]-[![Build badge][]][build]--- [Install](#install)-- [Use](#use)--## Install--1. Install [Stack][].--2. `stack install autoexporter`--## Use--Let's say you have a module `M` that just exports some other modules. It might-look like this:--``` haskell-module M- ( module M.A- , module M.B- ) where--import M.A-import M.B-```--This code is error-prone. If you add a new module, say `M.C`, you have to-remember to come back to this file and re-export it. And this code is tedious-to write. You have to list each module twice. You can do a little better, but-not much.--``` haskell-module M (module X) where-import M.A as X-import M.B as X-```--Now you don't have to write every module twice, but you still have to remember-to re-export everything. And the generated documentation for this module-doesn't include anything about the exported modules.--Autoexporter handles this for you. Instead of either of the above approaches,-simply drop this into the `M` module:--``` haskell-{-# OPTIONS_GHC -F -pgmF autoexporter #-}-```--That will generate code like the first example. A couple caveats:--- Only immediate children will be re-exported. If you use this in some module- `M`, it won't pull in `M.A.B`.--- You cannot selectively leave out any modules. You also cannot selectively- exclude any imports from any of the modules.-- - This could be allowed via `-optF`. I will happily accept patches for- this as well.--[Autoexporter]: https://github.com/tfausak/autoexporter-[Version badge]: https://www.stackage.org/package/autoexporter/badge/nightly?label=version-[version]: https://www.stackage.org/package/autoexporter-[Build badge]: https://travis-ci.org/tfausak/autoexporter.svg?branch=master-[build]: https://travis-ci.org/tfausak/autoexporter-[Stack]: http://haskellstack.org
autoexporter.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: autoexporter-version: 0.2.3+version: 1.0.0 synopsis: Automatically re-export modules. description: Autoexporter automatically re-exports modules. category: Utility@@ -11,14 +11,14 @@ bug-reports: https://github.com/tfausak/autoexporter/issues maintainer: Taylor Fausak license: MIT+license-file: LICENSE.markdown build-type: Simple cabal-version: >= 1.10 extra-source-files:- CHANGELOG.md- LICENSE.md+ CHANGELOG.markdown package.yaml- README.md+ README.markdown stack.yaml source-repository head@@ -27,7 +27,7 @@ library hs-source-dirs:- library+ source/library ghc-options: -Wall build-depends: base >=4.7 && <4.10@@ -41,7 +41,7 @@ executable autoexporter main-is: Main.hs hs-source-dirs:- executable+ source/executable ghc-options: -Wall build-depends: base
− executable/Main.hs
@@ -1,3 +0,0 @@-module Main (module Autoexporter) where--import Autoexporter (main)
− library/Autoexporter.hs
@@ -1,41 +0,0 @@-module Autoexporter (main) where--import qualified Data.List as List-import qualified Data.Maybe as Maybe-import qualified Distribution.ModuleName as ModuleName-import qualified Distribution.Text as Text-import qualified System.Directory as Directory-import qualified System.Environment as Environment-import qualified System.FilePath as FilePath--main :: IO ()-main = do- args <- Environment.getArgs- case args of- [name, inputFile, outputFile] -> do- let moduleName = makeModuleName name-- let directory = FilePath.dropExtension inputFile- files <- Directory.getDirectoryContents directory- let haskellFiles = filter (\ f -> List.isSuffixOf ".hs" f || List.isSuffixOf ".lhs" f) files- let paths = map (directory FilePath.</>) haskellFiles- let modules = List.sort (map makeModuleName paths)- let exports = init (unlines (map (\ x -> " module " ++ x ++ ",") modules))- let imports = init (unlines (map ("import " ++) modules))-- let output = unlines- [ unwords ["module", moduleName, "("]- , exports- , ") where"- , ""- , imports- ]- writeFile outputFile output- _ -> error ("unexpected arguments: " ++ show args)--makeModuleName :: FilePath -> String-makeModuleName name =- let path = FilePath.dropExtension name- parts = FilePath.splitDirectories path- rest = reverse (takeWhile (\ x -> Maybe.isJust (Text.simpleParse x :: Maybe ModuleName.ModuleName)) (reverse parts))- in List.intercalate "." rest
package.yaml view
@@ -6,12 +6,11 @@ - base - autoexporter main: Main.hs- source-dirs: executable+ source-dirs: source/executable extra-source-files:-- CHANGELOG.md-- LICENSE.md+- CHANGELOG.markdown - package.yaml-- README.md+- README.markdown - stack.yaml ghc-options: - -Wall@@ -22,9 +21,10 @@ - Cabal >=1.22 && <1.25 - directory >=1.2 && <1.4 - filepath >=1.3 && <1.5- source-dirs: library+ source-dirs: source/library license: MIT+license-file: LICENSE.markdown maintainer: Taylor Fausak name: autoexporter synopsis: Automatically re-export modules.-version: '0.2.3'+version: '1.0.0'
+ source/executable/Main.hs view
@@ -0,0 +1,5 @@+module Main+ ( module Autoexporter+ ) where++import Autoexporter (main)
+ source/library/Autoexporter.hs view
@@ -0,0 +1,72 @@+module Autoexporter where++import qualified Data.List as List+import qualified Data.Maybe as Maybe+import qualified Distribution.ModuleName as ModuleName+import qualified Distribution.Text as Text+import qualified System.Directory as Directory+import qualified System.Environment as Environment+import qualified System.FilePath as FilePath++main :: IO ()+main = do+ args <- Environment.getArgs+ mainWithArgs args++mainWithArgs :: [String] -> IO ()+mainWithArgs args =+ case args of+ [name, inputFile, outputFile] -> autoexport name inputFile outputFile+ _ -> fail ("unexpected arguments: " ++ show args)++autoexport :: String -> FilePath -> FilePath -> IO ()+autoexport name inputFile outputFile = do+ let moduleName = makeModuleName name+ let directory = FilePath.dropExtension inputFile+ files <- Directory.getDirectoryContents directory+ let output = makeOutput moduleName directory files+ writeFile outputFile output++makeModuleName :: FilePath -> String+makeModuleName name =+ let path = FilePath.dropExtension name+ parts = FilePath.splitDirectories path+ rest = takeWhileEnd isModuleName parts+ in List.intercalate "." rest++takeWhileEnd :: (a -> Bool) -> [a] -> [a]+takeWhileEnd p xs = reverse (takeWhile p (reverse xs))++isModuleName :: String -> Bool+isModuleName x = Maybe.isJust (parseModuleName x)++parseModuleName :: String -> Maybe ModuleName.ModuleName+parseModuleName = Text.simpleParse++makeOutput :: String -> FilePath -> [FilePath] -> String+makeOutput moduleName directory files =+ let haskellFiles = filter isHaskellFile files+ paths = map (directory FilePath.</>) haskellFiles+ modules = List.sort (map makeModuleName paths)+ in renderModule moduleName modules++isHaskellFile :: FilePath -> Bool+isHaskellFile x = List.isSuffixOf ".hs" x || List.isSuffixOf ".lhs" x++renderModule :: String -> [String] -> String+renderModule name modules =+ unlines'+ [ unwords ["module", name, "("]+ , unlines' (map renderExport modules)+ , ") where"+ , unlines' (map renderImport modules)+ ]++unlines' :: [String] -> String+unlines' = List.intercalate "\n"++renderExport :: String -> String+renderExport x = " module " ++ x ++ ","++renderImport :: String -> String+renderImport x = "import " ++ x
stack.yaml view
@@ -1,3 +1,1 @@-install-ghc: true-require-stack-version: ! '>=1.0.4'-resolver: lts-5.12+resolver: lts-7.14