pianola-0.1.0: Remotely controlling Java Swing applications

Safe HaskellNone

Pianola.Pianola

Synopsis

Documentation

type Glance m l o a = o -> LogicT (Produ l (Nullipotent m)) aSource

A Glance is just a kleisli arrow used to locate and extract particular elements of type a in a data structure of type o.

The following effects are allowed:

  • Nondeterminism and failure. A Glance can return more than one value (or zero values, with mzero). See the replusify function, which is a valid Glance.
  • Logging. A Glance can log messages of type l about the elements it encounters during search, even elements visited in search branches which ultimately fail to produce any results. See logmsg.
  • Interactions with the server through the monad m, but only interactions that don't change the state of the GUI. For example, getting a image capture of a window. See Nullipotent.

The following effects are forbidden:

  • Any kind of delay effect. Glances must return as soon as possible.
  • Interactions with the server which do change the state of the GUI. Note that you can target and return the actions of type Sealed which dangle on the branches of the source data structure. You just can't execute them inside a Glance. To actually execute them, pass the glance as an argument to poke.

missing :: Monad m => Glance m l o a -> Glance m l o ()Source

When the Glance passed as argument finds nothing, the returned glance finds a single (). When the Glance passed as argument finds one or more values, the returned Glance finds zero results.

This function can be used in combination with retryPeek1s to wait for the dissapearance of a component on screen.

collect :: (Monad m, MonadPlus n) => Glance m l o a -> Glance m l o (n a)Source

Takes all the values returned by a Glance and returns a new Glance in which those values have been collected in a MonadPlus (often a list). This is useful when we want to recover a list of components which meet certain criteria in order to compare them among themselves. For example, getting all the buttons present in a window and sorting them left to right by their position on the screen.

liftN :: Monad m => Glance m l (Nullipotent m a) aSource

Executes a Nullipotent action in the context of a Glance.

newtype Pianola m l o a Source

A computation which interacts which an external system represented locally by the type o, using actions on the monad m, emitting log messages of type l, and returning a value of type a.

The following effects are allowed:

  • Purely observational interactions with the external system. See peek.
  • Logging. Log messages are emitted in the middle of the computation, unlike in a Writer monad. See logmsg and logimg.
  • Failure. See pfail.
  • Delays. See sleep.
  • Actions in the m monad which actually change the external system, like clicking on a button of a GUI. See poke.

Instead of baking all possible effects into the base free monad, Pianola takes the approach of representing each effect using the Proxy type from the pipes package.

The order of the trasformers in the monad stack is not arbitrary. For example: it does not make sense for a log message to make the computation fail or to trigger actions against the external system, so the log producer is colocated closest to the base monad, where it doesn't have access to those kind of effects.

Another example: it can be conveniento to automatically introduce a delay after every action (see ralentize) or to automatically log each action (see autolog). Therefore, the Sealed action producer is in the outermost position, having access to all the effects.

To actually execute a Pianola, use a driver function like simpleDriver or a specialization of it.

Constructors

Pianola 

Fields

unPianola :: Produ (Sealed m) (Produ Delay (MaybeT (Produ l (Observer m l o)))) a
 

Instances

Monad (Pianola m l o) 
Functor (Pianola m l o) 
Monad m => Loggy (Pianola m LogEntry o) 

pfail :: Monad m => Pianola m l o aSource

Aborts a Pianola computation.

pmaybe :: Monad m => Pianola m l o a -> Pianola m l o (Maybe a) -> Pianola m l o aSource

If the second Pianola argument returns Nothing, the first one is executed. Often used in combination with pfail.

peek :: Monad m => Glance m l o a -> Pianola m l o aSource

Lifts a Glance into the Pianola monad.

peekMaybe :: Monad m => Glance m l o a -> Pianola m l o (Maybe a)Source

Like peek, but if the Glance returns zero results then Nothing is returned instead of failing and halting the whole computation.

retryPeek1s :: Monad m => Int -> Glance m l o a -> Pianola m l o (Maybe a)Source

Like peekMaybe, but the specified number of retries is performed before returning Nothing. There is an sleep of 1 second between each retry.

retryPeek :: Monad m => Pianola m l o u -> Int -> Glance m l o a -> Pianola m l o (Maybe a)Source

A more general version of retryPeek1s which intersperses any Pianola action between retries.

poke :: Monad m => Glance m l o (Sealed m) -> Pianola m l o ()Source

Takes a glance that extracts an action of type Sealed from a data structure, and returns a Pianola executing the action (when the Pianola is interpreted by some driver-like fuction like simpleDriver.)

pokeMaybe :: Monad m => Glance m l o (Sealed m) -> Pianola m l o (Maybe ())Source

Like poke, but if the Glance returns zero results then Nothing is returned instead of failing and halting the whole computation.

retryPoke1s :: Monad m => Int -> Glance m l o (Sealed m) -> Pianola m l o (Maybe ())Source

Like pokeMaybe, but the specified number of retries is performed before returning Nothing. There is an sleep of 1 second between each retry.

retryPoke :: Monad m => Pianola m l o u -> Int -> Glance m l o (Sealed m) -> Pianola m l o (Maybe ())Source

A more general version of retryPoke1s which intersperses any Pianola action between retries.

sleep :: Monad m => Delay -> Pianola m l o ()Source

Sleeps for the specified number of seconds

with :: Monad m => Glance m l o' o -> Pianola m l o a -> Pianola m l o' aSource

Expands the context of a Pianola using a Glance. Typical use: transform a Pianola whose context is a particular window to a Pianola whose context is the whole GUI, using a Glance which locates the window in the GUI.

 with glance1 $ peek glance2 

is equal to

 peek $ glance1 >=> glance2

with can be used to group peeks and pokes whose glances share part of thir paths in common:

 do
     poke $ glance1 >=> glance2
     poke $ glance1 >=> glance3

is equal to

 with glance1 $ do
     poke glance2
     poke glance3

withMaybe :: Monad m => Glance m l o' o -> Pianola m l o a -> Pianola m l o' (Maybe a)Source

Like with, but when the element targeted by the Glance doens't exist, the Pianola argument is not executed and Nothing is returned.

withRetry1s :: Monad m => Int -> Glance m l o' o -> Pianola m l o a -> Pianola m l o' (Maybe a)Source

Like withMaybe, but several attempts to locate the target of the glance are performed, with a separation of 1 second.

withRetry :: Monad m => Pianola m l o' u -> Int -> Glance m l o' o -> Pianola m l o a -> Pianola m l o' (Maybe a)Source

A more general withMaybe for which any Pianola action can be interstpersed between retries.

ralentize :: Delay -> Pianola m l o a -> Pianola m l o aSource

Takes a delay in seconds and a Pianola as parameters, and returns a ralentized Pianola in which the delay has been inserted after every action.

ralentizeByTag :: ([Tag] -> Bool) -> Delay -> Pianola m l o a -> Pianola m l o aSource

autolog :: Pianola m LogEntry o a -> Pianola m LogEntry o aSource

Modifies a Pianola so that the default tags associated to an action are logged automatically when the action is executed.

play :: Monad m => m o -> Pianola m l o a -> Produ Delay (MaybeT (Produ l m)) aSource

Unwinds all the Glances contained in a Pianola by supplying them with the monadic value passed as the first argument. When a Glance returns with more than one result, one of the results is selected in order to continue (TO DO: emit a warning when this happens). The log messages of the glances are fused with the Pianola's own log stream. All the Sealed actions are injected into the base monad. The delay and log effects remain uninjected.

Usually, clients should not call this function directly, but use a driver function like simpleDriver.