| Title: | Object Oriented R |
|---|---|
| Description: | Lightweight tools for building object-oriented R code. |
| Authors: | Steve Walker [aut, cre] |
| Maintainer: | Steve Walker <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.0.1 |
| Built: | 2026-05-19 05:54:23 UTC |
| Source: | https://github.com/canmod/oor |
Initialize an empty object.
Base(starting_environment = emptyenv())Base(starting_environment = emptyenv())
starting_environment |
An environment to enclose the empty object.
This enclosing environment is useful for making things other than |
Inherit from Base if you want to start
from an empty class
empty_object = Base() print(empty_object) names(empty_object) Printer = function(x) { self = Base() self$.x = x self$print = function() print(self$.x) return_object(self, "Printer") } printer = Printer("something to print") printer$print() SupportivePrinter = function(x) { self = Printer(x) self$print = function() { print(paste(sQuote(self$.x), "is a very nice thing to say")) } return_object(self, "Supportive") } supportive_printer = SupportivePrinter("something to print") supportive_printer$print()empty_object = Base() print(empty_object) names(empty_object) Printer = function(x) { self = Base() self$.x = x self$print = function() print(self$.x) return_object(self, "Printer") } printer = Printer("something to print") printer$print() SupportivePrinter = function(x) { self = Printer(x) self$print = function() { print(paste(sQuote(self$.x), "is a very nice thing to say")) } return_object(self, "Supportive") } supportive_printer = SupportivePrinter("something to print") supportive_printer$print()
Clean the environment of a method (or methods) so that they contain a single object – self – which is the environment defining an object
clean_method_environment(e)clean_method_environment(e)
e |
Environment containing methods in an object |
There is no return value. The function is called for its side-effect of cleaning a method environment.
Initialize an object with concrete implementations of abstract method definitions.
Implementation()Implementation()
Inherit
from Implementation (using the
implements utility function) if you want
your class to implement an Interface.
BinaryOperation = function() { self = Interface() self$operate = function(x = numeric(1L), y = numeric(1L)) return(numeric(1L)) return_object(self, "BinaryOperation") } Add = function() { self = implements(BinaryOperation) self$operate = function(x = numeric(1L), y = numeric(1L)) return(x + y) return_object(self, "Add") } Multiply = function() { self = implements(BinaryOperation) self$operate = function(x = numeric(1L), y = numeric(1L)) return(x * y) return_object(self, "Multiply") } Add()$operate(1, 1) Multiply()$operate(2, 2)BinaryOperation = function() { self = Interface() self$operate = function(x = numeric(1L), y = numeric(1L)) return(numeric(1L)) return_object(self, "BinaryOperation") } Add = function() { self = implements(BinaryOperation) self$operate = function(x = numeric(1L), y = numeric(1L)) return(x + y) return_object(self, "Add") } Multiply = function() { self = implements(BinaryOperation) self$operate = function(x = numeric(1L), y = numeric(1L)) return(x * y) return_object(self, "Multiply") } Add()$operate(1, 1) Multiply()$operate(2, 2)
Inherit methods and fields from other classes.
inherit_from(parent, traits, ...) implements(interface)inherit_from(parent, traits, ...) implements(interface)
parent |
A single class from which to inherit methods and fields. |
traits |
A vector of |
... |
Arguments to pass to the initialization of the |
interface |
Class definition that inherits from |
There are three ways to inherit from other classes:
(1) directly
(2) using the inherit_from function
(3) using the implements function
Each of these ways works by adding a line that creates an object called
self at the beginning of a class definition. The object self
is an object of class ParentClass and you are free to add new fields
and methods to this object.
self = ParentClass(...)
Here ParentClass is the name of the parent class being inherited from.
In most cases, direct inheritance is the most useful approach. The other
two are for more advanced use.
self = inherit_from(ParentClass, list_of_trait_classes)
Here ParentClass is the class being directly inherited from
and list_of_trait_classes is a list of Trait
classes containing methods to be forwarded to self.
self = implements(ParentInterface)
Here ParentInterface is an abstract set of method signatures.
Following this initialization, concrete definitions of these abstract
method need to be added to self. This process is referred to as
implementing an interface.
Initialize an empty abstract class.
Interface()Interface()
Inherit from Interface to define the
argument signatures and return value types
of abstract methods.
BinaryOperation = function() { self = Interface() self$operate = function(x = numeric(1L), y = numeric(1L)) return(numeric(1L)) return_object(self, "BinaryOperation") }BinaryOperation = function() { self = Interface() self$operate = function(x = numeric(1L), y = numeric(1L)) return(numeric(1L)) return_object(self, "BinaryOperation") }
Test inheritance
Is(class)Is(class)
class |
Name of a class to test for. |
Test that all MappedTest results are TRUE
MappedAllTest(basic_tester)MappedAllTest(basic_tester)
basic_tester |
An object that can be converted to a function |
Test that any MappedTest results are TRUE
MappedAnyTest(basic_tester)MappedAnyTest(basic_tester)
basic_tester |
An object that can be converted to a function |
Apply a Summarizer to each element of a list, in order
to test that a particular summary of each lists item meets a certain
criterion. MappedSummarizers are typically included in
TestPipelines.
MappedSummarizer(...)MappedSummarizer(...)
... |
A list of summarizing functions. |
Object of class Test that summarizes each
element of objects to test.
Apply a Test to each element of a list.
MappedTest(basic_tester, boolean_aggregator)MappedTest(basic_tester, boolean_aggregator)
basic_tester |
An object that can be converted to a function |
boolean_aggregator |
A function that summarizes a |
Call a method for each item in a list of objects.
method_apply(objects, method_name, ...)method_apply(objects, method_name, ...)
objects |
List of objects. |
method_name |
Character string giving the name of the method. |
... |
Arguments to pass to the method. |
Assess several criteria.
MultiTest(test_function_list, boolean_aggregator) All(...) Any(...)MultiTest(test_function_list, boolean_aggregator) All(...) Any(...)
test_function_list |
|
boolean_aggregator |
A function that summarizes a |
... |
Test functions. |
Object of class Test that tests several
criteria at the same time.
All(): Test that all of the criteria are met.
Any(): Test that any of the criteria are met.
is_matrix = All( is.numeric, TestPipeline( Summarizer(dim, length), TestRange(0, 2) ) ) is_matrix$apply(array("a", c(1))) # FALSE is_matrix$apply(array("a", c(1, 1, 2))) # FALSE is_matrix$apply(array(1, c(1, 1, 2))) # FALSE is_matrix$apply(array(1, c(1, 2))) # TRUE is_matrix$apply(1) # TRUEis_matrix = All( is.numeric, TestPipeline( Summarizer(dim, length), TestRange(0, 2) ) ) is_matrix$apply(array("a", c(1))) # FALSE is_matrix$apply(array("a", c(1, 1, 2))) # FALSE is_matrix$apply(array(1, c(1, 1, 2))) # FALSE is_matrix$apply(array(1, c(1, 2))) # TRUE is_matrix$apply(1) # TRUE
Not
Not(basic_tester)Not(basic_tester)
basic_tester |
An object that can be converted to a function |
Object of class Test that evaluates the
complement of basic_tester.
Not(is.numeric)$apply(1) # FALSE Not(is.numeric)$apply("1") # TRUENot(is.numeric)$apply(1) # FALSE Not(is.numeric)$apply("1") # TRUE
Experimental
return_facade(self, private, class)return_facade(self, private, class)
self |
New object. |
private |
Environment to use for containing private methods and fields. |
class |
String giving the class name. |
This should be the final function called in a class definition. Think of it like return(...)
return_object(self, class)return_object(self, class)
self |
New object. |
class |
String giving the class name. |
New object of class given by class.
Summarize an object to be tested, so that the test is applied to the
summary and not the object itself (e.g. length(dim(object)) == 2L).
Summarizers are typically included in TestPipelines.
Summarizer(...)Summarizer(...)
... |
A list of summarizing functions. |
Object of class Test that summarizes objects
to test.
Abstract Class Testing Objects
Test() ## S3 method for class 'Test' as.function(x, ...)Test() ## S3 method for class 'Test' as.function(x, ...)
x |
|
... |
Not used. Present for S3 method consistency. |
Object with an apply method that takes a single
argument, x, and returns a length-one logical vector.
Initialize an object with functionality for validating objects
Testable()Testable()
Inherit from Testable if you
would like your class to provide a validity
check. Validity checking often requires differentiating between public
versus private members, as well as fields versus methods.
Printer = function(x) { self = Testable() self$.x = x self$valid = function() { if (!is.character(self$.x)) { return("can only print character strings") } if (length(self$.x) != 1L) { return("can only print length-1 character vectors") } return(TRUE) } self$print = function() print(self$.x) return_object(self, "Printer") } printer = Printer("something to print") printer$print() try(Printer(0)) ## errorPrinter = function(x) { self = Testable() self$.x = x self$valid = function() { if (!is.character(self$.x)) { return("can only print character strings") } if (length(self$.x) != 1L) { return("can only print length-1 character vectors") } return(TRUE) } self$print = function() print(self$.x) return_object(self, "Printer") } printer = Printer("something to print") printer$print() try(Printer(0)) ## error
Basic Test
TestBasic(basic_tester)TestBasic(basic_tester)
basic_tester |
An object that can be converted to a function |
Object of class Test that evaluates
the basic_tester.
Test that all elements in an object are identical.
TestHomo()TestHomo()
Object of class Test that tests that all
elements in an object are identical.
Test Pipeline
TestPipeline(...)TestPipeline(...)
... |
Objects of class |
Object inheriting from Test
is_matrix = TestPipeline( Summarizer(dim, length), TestRange(0, 2) ) is_matrix$apply(array("a", c(1))) # TRUE is_matrix$apply(array(1, c(1, 2, 3))) # FALSE each_is_matrix = TestPipeline( MappedSummarizer(dim, length), All(TestRange(0, 2)) ) each_is_matrix$apply(list(1, matrix(1, 2, 3), "a")) # TRUE each_is_matrix$apply(list(1, array(1, c(2, 3, 4)), "a")) # FALSEis_matrix = TestPipeline( Summarizer(dim, length), TestRange(0, 2) ) is_matrix$apply(array("a", c(1))) # TRUE is_matrix$apply(array(1, c(1, 2, 3))) # FALSE each_is_matrix = TestPipeline( MappedSummarizer(dim, length), All(TestRange(0, 2)) ) each_is_matrix$apply(list(1, matrix(1, 2, 3), "a")) # TRUE each_is_matrix$apply(list(1, array(1, c(2, 3, 4)), "a")) # FALSE
Test that all elements in an object greater than or equal to lower
and less than or equal to upper.
TestRange(lower, upper)TestRange(lower, upper)
lower |
Lower bound |
upper |
Upper bound |
Object of class Test that tests that all
elements in an object numerically on a particular range.
Test that all elements in an object are in set
TestSubset(set)TestSubset(set)
set |
Universe of possibilities. |
Object of class Test that tests that all
elements in an object are in a particular set.
Initialize an object with methods that are intended to be forwarded to other classes.
Trait()Trait()
Inherit from Trait if you want to use
your class to forward public methods to other classes without direct
inheritance.
Print = function(x) { self = Testable() self$.x = x return_object(self, "Print") } Printer = function() { self = Trait() self$print = function() print(self$.x) return_object(self, "Printer") } PrintString = function(x) { self = inherit_from(Print, list(Printer), x) self$valid = function() { if (!is.character(self$.x)) return("can only print character strings") if (length(self$.x) != 1L) return("can only print length-1 character vectors") return(TRUE) } return_object(self, "PrintString") } PrintNumber = function(x) { self = inherit_from(Print, list(Printer), x) self$valid = function() { if (!is.numeric(self$.x)) return("can only print character strings") return(TRUE) } return_object(self, "PrintNumber") } PrintString("something to print")$print() PrintNumber(pi)$print() try(PrintNumber("not a number")) ## errorPrint = function(x) { self = Testable() self$.x = x return_object(self, "Print") } Printer = function() { self = Trait() self$print = function() print(self$.x) return_object(self, "Printer") } PrintString = function(x) { self = inherit_from(Print, list(Printer), x) self$valid = function() { if (!is.character(self$.x)) return("can only print character strings") if (length(self$.x) != 1L) return("can only print length-1 character vectors") return(TRUE) } return_object(self, "PrintString") } PrintNumber = function(x) { self = inherit_from(Print, list(Printer), x) self$valid = function() { if (!is.numeric(self$.x)) return("can only print character strings") return(TRUE) } return_object(self, "PrintNumber") } PrintString("something to print")$print() PrintNumber(pi)$print() try(PrintNumber("not a number")) ## error
S3 generic for checking the validity of a constructed object. should either return nothing or trigger an error.
validate_object(object)validate_object(object)
object |
Object to be validated. |
TODO – check $valid methods
Couple a test function with a failure message
ValidityMessager(test_function, ...)ValidityMessager(test_function, ...)
test_function |
Object that is coercible to a |
... |
Length-1 |
ValidityMessager objects have an assert method
with one argument, x. If the test function evaluates to
TRUE then the argument, x, is returned. If
it does not return TRUE then the failure message is given.
Object of class ValidityMessager containing a check
method that will return TRUE or fail with fail_message.
is_numeric = ValidityMessager(is.numeric, "not numeric") try(is_numeric$check("1")) HoldANumber = function(x) { self = Base() self$x = is_numeric$assert(x) return_object(self, "HoldANumber") } try(HoldANumber("a")) ## error message HoldANumber(1) ## successis_numeric = ValidityMessager(is.numeric, "not numeric") try(is_numeric$check("1")) HoldANumber = function(x) { self = Base() self$x = is_numeric$assert(x) return_object(self, "HoldANumber") } try(HoldANumber("a")) ## error message HoldANumber(1) ## success