settings 0.1.0.1 → 0.2.0.0
raw patch · 6 files changed
+33/−167 lines, 6 files
Files
- ChangeLog +3/−3
- NEWS +23/−0
- settings.cabal +3/−4
- src/Control/Debounce.hs +0/−61
- src/Data/Settings.hs +4/−42
- src/Data/Settings/Persist.hs +0/−57
ChangeLog view
@@ -1,15 +1,15 @@ The changes are recorded by the version control system, Darcs. To see a log quickly from the terminal, run: - $ darcs changes --repo http://darcs.rel4tion.org/repos/settings+ $ darcs changes --repo http://dev.rel4tion.org/fr33domlover/settings -There is also a web interface at <http://darcs.rel4tion.org> which, among other+There is also a web interface at <http://dev.rel4tion.org> which, among other things, can display the history log. To see the log in a local clone, first get a copy of the repository if you haven't yet: - $ darcs get http://darcs.rel4tion.org/repos/settings+ $ darcs get http://dev.rel4tion.org/fr33domlover/settings Then move into the newly created directory and run darcs:
NEWS view
@@ -3,6 +3,29 @@ +settings 0.2.0.0 -- 2015-09-17+==============================++General, build and documentation changes:++* (None)++New APIs, features and enhancements:++* Remove persistence API, this is now provided by the json-state package++Bug fixes:++* (None)++Dependency changes:++* (None)+++++ settings 0.1.0.1 -- 2015-09-14 ==============================
settings.cabal view
@@ -1,5 +1,5 @@ name: settings-version: 0.1.0.1+version: 0.2.0.0 synopsis: Runtime-editable program settings. description: This library aims to be a tool for constructing a settings management UI on@@ -27,17 +27,16 @@ source-repository head type: darcs- location: http://darcs.rel4tion.org/repos/settings/+ location: http://dev.rel4tion.org/fr33domlover/settings library exposed-modules: Data.Settings , Data.Settings.Interface , Data.Settings.Option- , Data.Settings.Persist , Data.Settings.Section , Data.Settings.Route , Data.Settings.Types- other-modules: Control.Debounce+ -- other-modules: -- other-extensions: build-depends: aeson , aeson-pretty >=0.7
− src/Control/Debounce.hs
@@ -1,61 +0,0 @@-{- This file is part of settings.- -- - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.- -- - ♡ Copying is an act of love. Please copy, reuse and share.- -- - The author(s) have dedicated all copyright and related and neighboring- - rights to this software to the public domain worldwide. This software is- - distributed without any warranty.- -- - You should have received a copy of the CC0 Public Domain Dedication along- - with this software. If not, see- - <http://creativecommons.org/publicdomain/zero/1.0/>.- -}---- | This is similar to the same module from "auto-update" package, except here--- the caller can pass a parameter to the debounced action. Also, the returned--- action comes in 2 versions.------ The first is non-blocking at the cost of a small chance a parameter isn't--- passed and is instead discarded. This can happen if the action is called--- from different threads simultanously. One empties the 'MVar', and the other--- happens to fill it first, and then the parameter the former thread passed is--- discarded. If you run the action from a single thread, there is no problem,--- or if missing at a hopefully small chance isn't a problem.------ The second is blocking, but only in the small chance described above.--- Otherwise it doesn't block in practice.------ Also, exceptions aren't handled. This includes async exceptions and any--- exceptions thrown by the given action.-module Control.Debounce- ( mkDebounce- )-where--import Control.Monad (forever, void)-import Control.Concurrent (forkIO, threadDelay)-import Control.Concurrent.MVar-import Data.Time.Units--mkDebounce :: TimeUnit t- => t -- ^ Time delay between calls to the action- -> (a -> IO ()) -- ^ Action to perform- -> IO ( a -> IO () -- Never-blocking version- , a -> IO () -- Possibly-blocking version- )-mkDebounce interval action = do- paramVar <- newEmptyMVar- let run = forkIO $ forever $ do- param <- takeMVar paramVar- action param- threadDelay $ fromInteger $ toMicroseconds interval- actNB param = do- tryTakeMVar paramVar- void $ tryPutMVar paramVar param- actPB param = do- tryTakeMVar paramVar- putMVar paramVar param- run- return (actNB, actPB)
src/Data/Settings.hs view
@@ -37,11 +37,9 @@ -- -- The idea is that you freely use whatever you like for the settings values, -- and the settings tree is a UI component added on top without interfering--- with your program logic code. Persistence using periodic exports to JSON is--- provided in the "Data.Settings.Persist" module, but you can use any other--- solution as needed, e.g. the acid-state package. The persistence module is--- unrelated to the settings tree, and should probably move into its own--- package and get some extra features missing right now, like version control.+-- with your program logic code. Persistence using simple periodic exports to+-- JSON is available in the @json-state@ package, but you can use any other+-- solution as needed, e.g. the acid-state package. -- -- == Settings Tree Basics --@@ -266,9 +264,6 @@ -- The last argument is a callback action to be run when a successful set or -- reset of the value occurs. ----- We are done with the basics. Another 2 aspects of the library are settings--- tree modification and persistence.--- -- == Settings Tree Dynamic Modification -- -- Modification simply requires holding the tree as application state, and@@ -276,37 +271,4 @@ -- API in "Data.Settings.Section" for working with the settings tree, and since -- unordered maps are being used, you may also find "Data.HashMap.Lazy" useful -- (from unordered-containers package).------ == Settings Persistence------ Finally, persistence. "Data.Settings.Persist" provides a function for--- loading the settings value from a JSON file, and a function which generates--- a safe scalable saver function. The JSON files are written using the--- @aeson-pretty@ package, so that they are easy to read and modify manually if--- needed.------ The save function generator, @mkSaveSettings@, returns a function which--- saves settings when called, but only at most once in @t@, the time interval--- passed to the generator. For example, if you pass an interval of 3 seconds,--- you can safely call the generated save function even 100 times a second, and--- the JSON file will still get updated just once in 3 seconds, avoiding an--- overload of file I/O.------ The actual saving happens in a dedicated worker thread, so even when a save--- does occur, it won't block the caller thread. You can, for example, call the--- save function in the callback you pass to @mkOptionS@. The generator can be--- called once at program start, and the returned save function saved in--- application state.------ Using the persistence module requires that you define @FromJSON@ and--- @ToJSON@ instances for your settings type, see the @aeson@ package.------ Note that while this simple periodic save-to-file method can serve a simple--- standalone application well, it won't work if you wish your settings to be--- shared by multiple applications and allow them to read and write settings at--- the same time. If that's the case, check out the @acid-state@ package, and--- other persistence related packages.-module Data.Settings- (- )-where+module Data.Settings where
− src/Data/Settings/Persist.hs
@@ -1,57 +0,0 @@-{- This file is part of settings.- -- - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.- -- - ♡ Copying is an act of love. Please copy, reuse and share.- -- - The author(s) have dedicated all copyright and related and neighboring- - rights to this software to the public domain worldwide. This software is- - distributed without any warranty.- -- - You should have received a copy of the CC0 Public Domain Dedication along- - with this software. If not, see- - <http://creativecommons.org/publicdomain/zero/1.0/>.- -}--module Data.Settings.Persist- ( mkSaveSettings- , loadSettings- )-where--import Control.Debounce (mkDebounce)-import Control.Monad (liftM)-import qualified Data.ByteString.Lazy as B-import Data.Aeson (FromJSON, ToJSON, eitherDecode)-import Data.Aeson.Encode.Pretty (encodePretty)-import Data.Time.Units (TimeUnit)-import System.IO.Error (tryIOError)--saveAction :: ToJSON s => FilePath -> s -> IO ()-saveAction file s = B.writeFile file $ encodePretty s---- | Prepare a save action which writes settings into a JSON file. This action--- defers the work to a separate dedicated thread, and ensures the file isn't--- saved more than once within the given time interval.------ The action is non-blocking but there is a chance a save is missed if saves--- are triggered ------ You can call the returned action from your UI thread as a reaction to a--- settings change, without worrying about delay or IO load.-mkSaveSettings :: (TimeUnit t, ToJSON s) => t -> FilePath -> IO (s -> IO ())-mkSaveSettings interval file =- liftM fst $ mkDebounce interval (saveAction file)---- | Try to load settings from a file.------ If an error occurs, 'Left' a pair is returned. The boolean indicates whether--- reading the file failed ('False') or parsing the content failed ('True').--- The string is an error description.------ If the operation succeeds, 'Right' the loaded settings are returned.-loadSettings :: FromJSON s => FilePath -> IO (Either (Bool, String) s)-loadSettings file = do- errOrStr <- tryIOError (B.readFile file)- let pairOrStr = either (Left . (,) False . show) Right errOrStr- return $ pairOrStr >>= either (Left . (,) True) Right . eitherDecode