Skip to content

Commit

Permalink
Merge pull request #21 from mihaiconstantin/refactor
Browse files Browse the repository at this point in the history
Refactoring and minor fixes
  • Loading branch information
mihaiconstantin committed Mar 15, 2023
2 parents 0b88f29 + e4d76d6 commit 3e55fcc
Show file tree
Hide file tree
Showing 23 changed files with 145 additions and 92 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Collate:
'BasicBar.R'
'BarFactory.R'
'Context.R'
'ProgressDecorator.R'
'ProgressTrackingContext.R'
'ContextFactory.R'
'Warning.R'
'exports.r'
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export(Helper)
export(LOGO)
export(ModernBar)
export(Options)
export(ProgressDecorator)
export(ProgressTrackingContext)
export(Service)
export(Specification)
export(SyncBackend)
Expand Down
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
active binding to a desired path.

## Changed
- Replace `\dontrun{}` statements in examples with `try()` calls.
- Update example for `Options` class to feature the `progress_log_path` active
binding.
- Update progress logging injection approach in `.decorate` method of
`ProgressTrackingContext` to use `bquote` instead of `substitute`.
- **Breaking**. Rename class `ProgressDecorator` to `ProgressTrackingContext` to
be more consistent with the idea of *backends* that run in *contexts*.
- Add `...` optional arguments to signature of `get_output` method in `Service`
interface.
- Update private method `.make_log` of `ProgressDecorator` to use the
`progress_log_path` option.
- Update `UML` diagram to include missing classes and changed methods. Also
Expand Down
4 changes: 2 additions & 2 deletions R/AsyncBackend.R
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
#'
#' # Trying to get the output immediately will throw an error, indicating that the
#' # task is still running.
#' \dontrun{backend$get_output()}
#' try(backend$get_output())
#'
#' # However, we can block the main process and wait for the task to complete
#' # before fetching the results.
Expand All @@ -84,7 +84,7 @@
#'
#' @seealso
#' [`parabar::Service`], [`parabar::Backend`], [`parabar::SyncBackend`],
#' [`parabar::ProgressDecorator`], and [`parabar::TaskState`].
#' [`parabar::ProgressTrackingContext`], and [`parabar::TaskState`].
#'
#' @export
AsyncBackend <- R6::R6Class("AsyncBackend",
Expand Down
6 changes: 3 additions & 3 deletions R/Context.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#' It registers a backend instance and forwards all [`parabar::Service`] methods
#' calls to the backend instance. Subclasses can override any of the
#' [`parabar::Service`] methods to decorate the backend instance with additional
#' functionality (e.g., see the [`parabar::ProgressDecorator`] class).
#' functionality (e.g., see the [`parabar::ProgressTrackingContext`] class).
#'
#' @examples
#' # Define a task to run in parallel.
Expand Down Expand Up @@ -78,8 +78,8 @@
#' context$stop()
#'
#' @seealso
#' [`parabar::ProgressDecorator`], [`parabar::Service`], [`parabar::Backend`],
#' and [`parabar::SyncBackend`].
#' [`parabar::ProgressTrackingContext`], [`parabar::Service`],
#' [`parabar::Backend`], and [`parabar::SyncBackend`].
#'
#' @export
Context <- R6::R6Class("Context",
Expand Down
10 changes: 5 additions & 5 deletions R/ContextFactory.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#' @include Exception.R Context.R ProgressDecorator.R
#' @include Exception.R Context.R ProgressTrackingContext.R

# Factory for fetching context instances (i.e., for managing and decorating backends).
#' @title BackendFactory
Expand All @@ -22,8 +22,8 @@
#' class(context)
#'
#' @seealso
#' [`parabar::Context`], [`parabar::ProgressDecorator`], [`parabar::Service`],
#' and [`parabar::Backend`]
#' [`parabar::Context`], [`parabar::ProgressTrackingContext`],
#' [`parabar::Service`], and [`parabar::Backend`]
#'
#' @export
ContextFactory <- R6::R6Class("ContextFactory",
Expand All @@ -38,7 +38,7 @@ ContextFactory <- R6::R6Class("ContextFactory",
#' @details
#' When `type = "regular"` a [`parabar::Context`] instance is created
#' and returned. When `type = "progress"` a
#' [`parabar::ProgressDecorator`] instance is provided instead.
#' [`parabar::ProgressTrackingContext`] instance is provided instead.
#'
#' @return
#' An object of type [`parabar::Context`]. It throws an error if the
Expand All @@ -47,7 +47,7 @@ ContextFactory <- R6::R6Class("ContextFactory",
return(
switch(type,
regular = Context$new(),
progress = ProgressDecorator$new(),
progress = ProgressTrackingContext$new(),
Exception$feature_not_developed()
)
)
Expand Down
26 changes: 22 additions & 4 deletions R/Options.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,38 @@
#' # To restore defaults, set the default options again.
#' set_default_options()
#'
#' # Check that the change was applied (i.e., `progress_track: FALSE`).
#' # Check that the change was applied (i.e., `progress_track: TRUE`).
#' getOption("parabar")
#'
#' # We can also use the built-in helpers to get and set options more conveniently.
#'
#' # Get the progress tracking option.
#' get_option("progress_track")
#'
#' # Set the progress tracking option to `TRUE`.
#' set_option("progress_track", TRUE)
#' # Set the progress tracking option to `FALSE`.
#' set_option("progress_track", FALSE)
#'
#' # Check that the change was applied (i.e., `progress_track: TRUE`).
#' # Check that the change was applied (i.e., `progress_track: FALSE`).
#' get_option("progress_track")
#'
#' # Get a temporary file for logging the progress.
#' get_option("progress_log_path")
#'
#' # Fix the logging file path.
#' set_option("progress_log_path", "./progress.log")
#'
#' # Check that the logging path change was applied.
#' get_option("progress_log_path")
#'
#' # Restore the logging path to the default behavior.
#' set_option("progress_log_path", NULL)
#'
#' # Check that the logging path change was applied.
#' get_option("progress_log_path")
#'
#' # Restore the defaults.
#' set_default_options()
#'
#' @seealso [parabar::get_option()], [parabar::set_option()], and
#' [parabar::set_default_options()].
#'
Expand Down
25 changes: 11 additions & 14 deletions R/ProgressDecorator.R → R/ProgressTrackingContext.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#' @include Context.R Bar.R

#' @title
#' ProgressDecorator
#' ProgressTrackingContext
#'
#' @description
#' This class represents a progress tracking context for interacting with
Expand Down Expand Up @@ -50,10 +50,10 @@
#' backend <- backend_factory$get("sync")
#'
#' # Create a progress tracking context object.
#' context <- ProgressDecorator$new()
#' context <- ProgressTrackingContext$new()
#'
#' # Attempt to set the incompatible backend instance.
#' \dontrun{context$set_backend(backend)}
#' try(context$set_backend(backend))
#'
#' # Get a backend instance that does support progress tracking.
#' backend <- backend_factory$get("async")
Expand Down Expand Up @@ -110,7 +110,7 @@
#' [`parabar::AsyncBackend`].
#'
#' @export
ProgressDecorator <- R6::R6Class("ProgressDecorator",
ProgressTrackingContext <- R6::R6Class("ProgressTrackingContext",
inherit = Context,

private = list(
Expand Down Expand Up @@ -140,28 +140,28 @@ ProgressDecorator <- R6::R6Class("ProgressDecorator",

# Decorate task function to log the progress after each execution.
.decorate = function(task, log) {
# Determine file log lock path.
log_lock_path <- paste0(log, ".lock")

# Get the body of the function to patch.
fun_body <- body(task)

# Get the length of the body.
length_fun_body <- length(fun_body)

# Insert the expression.
fun_body[[length_fun_body + 1]] <- substitute(
fun_body[[length_fun_body + 1]] <- bquote(
# The injected expression.
on.exit({
# Acquire an exclusive lock.
log_lock <- filelock::lock(log_lock_path)
log_lock <- filelock::lock(.(log_lock_path))

# Write the line.
cat("\n", file = log, sep = "", append = TRUE)
cat("\n", file = .(log), sep = "", append = TRUE)

# Release the lock.
filelock::unlock(log_lock)
}),

# The environment to use for substitution.
parent.frame(n = 1)
})
)

# Reorder the body.
Expand Down Expand Up @@ -280,9 +280,6 @@ ProgressDecorator <- R6::R6Class("ProgressDecorator",
# Create file for logging progress.
log <- private$.make_log()

# Determine file log lock path.
log_lock_path <- paste0(log, ".lock")

# Clear the temporary file on function exit.
on.exit({
# Remove.
Expand Down
5 changes: 4 additions & 1 deletion R/Service.R
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,13 @@ Service <- R6::R6Class("Service",
#' not advised. This method should be called after the execution of a
#' task.
#'
#' @param ... Additional optional arguments that may be used by concrete
#' implementations.
#'
#' @return
#' A vector or list of the same length as `x` containing the results of
#' the `fun`. It resembles the format of [base::sapply()].
get_output = function() {
get_output = function(...) {
Exception$method_not_implemented()
}
)
Expand Down
2 changes: 1 addition & 1 deletion R/TaskState.R
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
#' backend$stop()
#'
#' @seealso
#' [`parabar::AsyncBackend`] and [`parabar::ProgressDecorator`].
#' [`parabar::AsyncBackend`] and [`parabar::ProgressTrackingContext`].
#'
#' @export
TaskState <- R6::R6Class("TaskState",
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ A **`context`** represents the specific conditions in which a backend object
operates. The default context class (i.e., `?Context`) simply forwards the call
to the corresponding backend method. However, a more complex context can augment
the operation before forwarding the call to the backend. One example of a
complex context is the `?ProgressDecorator` class. This class extends the
complex context is the `?ProgressTrackingContext` class. This class extends the
regular `?Context` class and decorates the backend `sapply` operation to log the
progress after each task execution and display a progress bar.

Expand All @@ -323,8 +323,8 @@ The following are the main classes provided by
- `BackendFactory`: Factory for creating `Backend` objects.
- `Context`: Default context for executing backend operations without
interference.
- `ProgressDecorator`: Context for decorating the `sapply` operation to track
and display the progress.
- `ProgressTrackingContext`: Context for decorating the `sapply` operation to
track and display the progress.
- `ContextFactory`: Factory for creating `Context` objects.

Additionally, [`parabar`](https://parabar.mihaiconstantin.com) also provides
Expand Down Expand Up @@ -419,9 +419,9 @@ context$set_backend(backend)
The `?Context` class (i.e., and it's subclasses) implements the `?Service`
interface, which means that we can use it to execute backend operations.

Since we are using the `?ProgressDecorator` context, we also need to register a
`?Bar` instance with the context. First, let's obtain a `?Bar` instance from the
`?BarFactory`.
Since we are using the `?ProgressTrackingContext` context, we also need to
register a `?Bar` instance with the context. First, let's obtain a `?Bar`
instance from the `?BarFactory`.

```r
# Create a bar factory.
Expand Down
2 changes: 1 addition & 1 deletion _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ reference:
- BackendFactory
- Specification
- Context
- ProgressDecorator
- ProgressTrackingContext
- ContextFactory
- TaskState
- Bar
Expand Down
2 changes: 1 addition & 1 deletion man-roxygen/par-sapply.R
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#' - Instantiates an appropriate [`parabar::parabar`] context. If the backend
#' supports progress tracking (i.e., the backend is an instance of
#' [`parabar::AsyncBackend`]), a progress tracking context (i.e.,
#' [`parabar::ProgressDecorator`]) is instantiated and used. Otherwise, a
#' [`parabar::ProgressTrackingContext`]) is instantiated and used. Otherwise, a
#' regular context (i.e., [`parabar::Context`]) is instantiated. A regular
#' context is also used if the progress tracking is disabled via the
#' [`parabar::Options`] instance.
Expand Down
10 changes: 5 additions & 5 deletions man-roxygen/parabar.R
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@
#' operates. The default, regular [`parabar::Context`] class simply forwards the
#' call to the corresponding backend method. However, a more complex context can
#' augment the operation before forwarding the call to the backend. One example
#' of a complex context is the [`parabar::ProgressDecorator`] class. This class
#' extends the regular [`parabar::Context`] class and decorates the backend
#' [`sapply()`][parabar::Service] operation to log the progress after each task
#' execution and display a progress bar.
#' of a complex context is the [`parabar::ProgressTrackingContext`] class. This
#' class extends the regular [`parabar::Context`] class and decorates the
#' backend [`sapply()`][parabar::Service] operation to log the progress after
#' each task execution and display a progress bar.
#'
#' The following are the main classes provided by `parabar`:
#' - [`parabar::Service`]: interface for backend operations.
Expand All @@ -85,7 +85,7 @@
#' asynchronous backend.
#' - [`parabar::BackendFactory`]: factory for creating backend objects.
#' - [`parabar::Context`]: default context for executing backend operations.
#' - [`parabar::ProgressDecorator`]: context for decorating the
#' - [`parabar::ProgressTrackingContext`]: context for decorating the
#' [`sapply()`][parabar::Service] operation to track and display progress.
#' - [`parabar::ContextFactory`]: factory for creating context objects.
#'
Expand Down
4 changes: 2 additions & 2 deletions man/AsyncBackend.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/Context.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/ContextFactory.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3e55fcc

Please sign in to comment.