This package provides functions to clean import lists, to split up modules, and to merge modules. The important entry points are:
There are several features worth noting. The
Params type in the
MonadClean has a
removeEmptyImports field, which is
True by default. This determines whether imports that turn into
empty lists are preserved or not - if your program needs instances
from a such an import, you will either want to set this flag to
False or (better) add an empty import list to the import.
These are the important entry points:
runCleanT- Sets up the environment for splitting and merging. These operations require updates to be made to all the modules that import the modules being split or merged, so this environment tracks the creation and removal of modules. This allows a sequence of splits and merges to be performed without forgetting to update newly created modules.
cleanImports- uses ghc's -ddump-minimal-imports flag to generate minimized and explicit imports and re-insert them into the module.
splitModule- Splits a module into two or more parts according to the argument function.
splitModulewith a default first argument. Each declaration goes into a different module, and separate modules are created for instances and re-exports. Decls that were local to the original module go into a subdirectory named
Internal. Symbols which can't be turned into valid module names go into
mergeModules- the inverse operation of
splitModule, it merges two or more modules into a new or existing module, updating imports of the moduVerse elements as necessary.
findHsFiles ["Language", "Tests.hs", "Tests"] >>= runCleanT . cleanImports
- Split the module
Language.Haskell.Modules.Common, and then merge two of the declarations back in:
:m +Language.Haskell.Exts.Syntax findHsModules ["Language", "Tests.hs", "Tests"] >>= \ modules -> runCleanT $ mapM putModule modules >> splitModuleDecls "Language/Haskell/Modules/Common.hs" >> mergeModules [ModuleName "Language.Haskell.Modules.Common.WithCurrentDirectory", ModuleName "Language.Haskell.Modules.Common.Internal.ToEq"] (ModuleName "Language.Haskell.Modules.Common")
- Move two declarations from Internal to Common. The intermediate module
Tmpis used because using existing modules for a split is not allowed. The exception to this is that you can leave declarations in the original module.
findHsModules ["Language", "Tests.hs", "Tests"] >>= \ modules -> runCleanT $ mapM putModule modules >> splitModule (\ n -> if elem n [Just (Ident "ModuleResult"), Just (Ident "doResult")] then ModuleName "Tmp" else ModuleName "Language.Haskell.Modules.Internal") (ModuleName "Language/Haskell/Modules/Internal.hs") >> mergeModules [ModuleName "Language.Haskell.Modules.Common", ModuleName "Tmp"] (ModuleName "Language.Haskell.Modules.Common")
- cleanImports :: MonadClean m => [FilePath] -> m [ModuleResult]
- splitModule :: MonadClean m => (Maybe Name -> ModuleName) -> FilePath -> m [ModuleResult]
- splitModuleDecls :: MonadClean m => FilePath -> m [ModuleResult]
- defaultSymbolToModule :: ModuleInfo -> Maybe Name -> ModuleName
- mergeModules :: MonadClean m => [ModuleName] -> ModuleName -> m [ModuleResult]
- class (MonadIO m, MonadCatchIO m, Functor m) => MonadClean m
- type CleanT m = StateT Params m
- runCleanT :: MonadCatchIO m => CleanT m a -> m a
- putModule :: (ModuVerse m, MonadVerbosity m) => String -> m ()
- findModule :: (ModuVerse m, MonadVerbosity m) => String -> m (Maybe ModuleInfo)
- modifyDryRun :: MonadClean m => (Bool -> Bool) -> m ()
- modifyHsFlags :: MonadClean m => ([String] -> [String]) -> m ()
- modifyRemoveEmptyImports :: MonadClean m => (Bool -> Bool) -> m ()
- modifyExtensions :: ModuVerse m => ([Extension] -> [Extension]) -> m ()
- modifyTestMode :: MonadClean m => (Bool -> Bool) -> m ()
- modifyDirs :: SourceDirs m => ([FilePath] -> [FilePath]) -> m ()
- putDirs :: SourceDirs m => [FilePath] -> m ()
- noisily :: MonadVerbosity m => m a -> m a
- quietly :: MonadVerbosity m => m a -> m a
- modulePathBase :: String -> ModuleName -> FilePath
- findHsModules :: [FilePath] -> IO [String]
- findHsFiles :: [FilePath] -> IO [FilePath]
- withCurrentDirectory :: MonadCatchIO m => FilePath -> m a -> m a
Clean up the imports of a source file.
|:: MonadClean m|
|=> (Maybe Name -> ModuleName)|
Map declaration to new module name. The name
|-> m [ModuleResult]|
Split each of a module's declarations into a new module. Update the imports of all the modules in the moduVerse to reflect the split. For example, if you have a module like
module Start (a, b, (.+.)) where import a = 1 + a b = 2 c = 3 c' = 4 (.+.) = b + c
splitModuleDecls Start.hs the
Start module will
be gone. The
b symbols will be in new modules named
Start.B. Because they were not exported by
c' symbols will both be in a new module
Start.Internal.C. And the
.+. symbol will be in a module
Start.OtherSymbols. Note that this module needs to import
If we had imported and then re-exported a symbol in Start it would
go into a module named
Start.ReExported. Any instance declarations
would go into
Do splitModuleBy with the default symbol to module mapping (was splitModule)
This can be used to build function parameter of splitModule, it determines which module should a symbol be moved to.
Merge the declarations from several modules into a single new one, updating the imports of the modules in the moduVerse to reflect the change. It *is* permissable to use one of the input modules as the output module. Note that circular imports can be created by this operation.
Create the environment required to do import cleaning and module splitting/merging. This environment, StateT Params m a, is an instance of MonadClean.
Controls whether file updates will actually be performed. Default is False. (I recommend running in a directory controlled by a version control system so you don't have to worry about this.)
Modify the list of extra flags passed to GHC. Default is
If this flag is set, imports that become empty are removed.
Sometimes this will lead to errors, specifically when an instance
in the removed import that was required is no longer be available.
(Note that this reflects a limitation of the
-ddump-minimal-imports option of GHC.) If this happens this flag
should be set. Note that an import that is already empty when
cleanImports runs will never be removed, on the assumption that
it was placed there only to import instances. Default is True.
If TestMode is turned on no import cleaning will occur after a split or cat. Default is False.
Convenience function for building the moduVerse, searches for modules in a directory hierarchy. FIXME: This should be in MonadClean and use the value of sourceDirs to remove prefixes from the module paths. And then it should look at the module text to see what the module name really is.
Find the paths of all the files below the directory