LLVariables
Answers questions about ONE variable of a dictionary: the row it sits on, the value of any column on that row, and the named fields the rest of the tree reads most. Contains says whether a variable name is in the dictionary, Index gives its row, Value reads any column of that row and SetValue writes one, CellRange answers the cell, and SheetName, ControlType and TableName answer the three named fields. VariableNames lists every name the dictionary holds.
WHAT THE INSTANCE HOLDS
The variable-name column and the header row are each read once as a block, and every lookup after that is a string compare in memory.
The names are held until InvalidateCaches. LLdictionary.Prepare inserts geo rows, so an object built before preparation answers over the dictionary as it stood then. EventSetup is the one production caller that drops the held names.
The header row is held too. A column the held row cannot answer makes the header row be read again before the answer is "missing", so a column added after this object was built resolves. A column the held row CAN answer is checked with one cell read before its index is handed out, so a header renamed on the worksheet is seen.
Depends on: BetterArray, Checking, DataSheet, LLdictionary
Creation
Create #
create
Build a variables reader over one dictionary
Signature:
Public Function Create(ByVal dict As LLdictionary) As LLVariables
Validates the dictionary before anything else: a missing object, a dictionary
with no DataSheet, and a dictionary with no "variable name" column each
raise their own error. TestLLVariables pins all three numbers.
Parameters:
dict: LLdictionary. The dictionary to read.
Returns: LLVariables. A sealed instance bound to that dictionary.
Throws:
- ProjectError.InvalidArgument When dict is Nothing.
- ProjectError.ObjectNotInitialized When the dictionary has no DataSheet.
- ProjectError.ElementNotFound When the variable-name column is missing.
Dictionary #
dictionary
Dictionary this object reads
Signature:
Public Property Get Dictionary() As LLdictionary
Returns: LLdictionary
Cache management
InvalidateCaches #
Drop everything this object holds about the worksheet
Signature:
Public Sub InvalidateCaches()
The two snapshots and the host worksheet live here. Read the class header for what each one promises.
The way out for a caller that changed the dictionary behind this object:
EventSetup calls it after the setup sheets are rebuilt. The search range
goes too, so the next read rebuilds it from the dictionary.
Reading
Contains #
contains
Test whether a variable is in the dictionary
Signature:
Public Function Contains(ByVal varName As String, Optional ByVal matchCase As Boolean = True) As Boolean
Case-sensitive by default. LLdictionary.UniqueVarNames normalises variable
names during preparation, so the stored case is whatever the user typed, and
LLSheets.VariableAddress and LLExport.ResolveVariableChunk both rely on
the case-sensitive answer.
The match is a string compare in memory, so a name holding *, ?, [, ]
or # is matched as written. The Range.Find this replaced had to escape
those characters first.
Parameters:
varName: String. Variable to look for.matchCase: Optional Boolean. When True, the match is case-sensitive. Defaults to True.
Returns: Boolean. True when the variable is present.
Value #
value
Value of one column for one variable
Signature:
Public Function Value(ByVal colName As String, ByVal varName As String) As String
The argument order is column first. Twenty production sites call it with named arguments, so both names are part of the contract.
Parameters:
colName: String. Column header.varName: String. Variable name.
Returns: String. The cell text, or an empty string when either is missing.
SheetName #
Sheet a variable belongs to
Signature:
Public Function SheetName(ByVal varName As String, Optional ByVal matchCase As Boolean = True) As String
Parameters:
varName: String. Variable name.matchCase: Optional Boolean. When True, the variable match is case-sensitive. Defaults to True.
Returns: String. The sheet name, or an empty string.
ControlType #
Control type of a variable
Signature:
Public Function ControlType(ByVal varName As String, Optional ByVal matchCase As Boolean = True) As String
Parameters:
varName: String. Variable name.matchCase: Optional Boolean. When True, the variable match is case-sensitive. Defaults to True.
Returns: String. The control value, or an empty string.
TableName #
Table a variable belongs to
Signature:
Public Function TableName(ByVal varName As String) As String
The table name column is written by LLdictionary.Prepare, so this answers
an empty string on a dictionary that has not been prepared.
Parameters:
varName: String. Variable name.
Returns: String. The table name, or an empty string.
CellRange #
cell-range
Cell holding one column of one variable
Signature:
Public Property Get CellRange(ByVal colName As String, ByVal varName As String) As Range
Parameters:
colName: String. Column header.varName: String. Variable name.
Returns: Range. The cell, or Nothing when the row or the column is missing.
VariableNames #
List of every variable name in the dictionary
Signature:
Public Function VariableNames() As BetterArray
Built from the snapshot, so it costs no worksheet read once the column has been loaded. Empty cells are left out.
Returns: BetterArray. The names, lower bound 1.
Writing
SetValue #
Write one column of one variable
Signature:
Public Function SetValue(ByVal varName As String, _
ByVal colName As String, _
ByVal newValue As String, _
Optional ByVal onEmpty As Boolean = False) As Boolean
onEmpty tests IsEmpty on the target cell. That is False for a cell holding
an empty string and for a formula that returns "", which is the behaviour
LinelistSpecs relies on for the "list auto" column.
The return value says whether the write happened. A skipped write used to be
recorded in a checking object that nothing ever read.
Parameters:
varName: String. Variable to write to.colName: String. Column header to write to.newValue: String. The value to write.onEmpty: Optional Boolean. When True, write only into an empty cell. Defaults to False.
Returns: Boolean. True when the value was written.
Throws:
- ProjectError.ElementNotFound When the variable or the column is missing.
Index #
index
Column index of a variable on its own sheet
Signature:
Public Function Index(ByVal varName As String) As Long
Reads the "column index" column, which LLdictionary.Prepare creates. Before
preparation the cell is empty and this raises ElementNotFound; that is the
contract LLSheets.VariableAddress turns into its own message.
Parameters:
varName: String. Variable name.
Returns: Long. The index stored for that variable.
Throws:
- ProjectError.ElementNotFound When the column index is missing.
- ProjectError.InvalidArgument When the stored index is not a number.
Internal members (not exported)
Creation
Dictionary #
dictionary-set
Bind the dictionary, at creation only
Signature:
Public Property Set Dictionary(ByVal dict As LLdictionary)
Parameters:
dict: LLdictionary. The dictionary to read.
Seal #
seal
Prevent further changes to creation-only setters
Signature:
Public Sub Seal()
GuardNotSealed #
guard-not-sealed
Refuse a write to a creation-only setter
Signature:
Private Sub GuardNotSealed(ByVal propName As String)
Parameters:
propName: String. Name used in the message.
Throws:
- ProjectError.SomethingWentWrong When the instance is already sealed.
Cache management
DropSnapshots #
drop-snapshots
Forget the two blocks and the host worksheet
Signature:
Private Sub DropSnapshots()
EnsureDictionaryReady #
Refuse to read without a dictionary
Signature:
Private Sub EnsureDictionaryReady()
Throws:
- ProjectError.ObjectNotInitialized When no dictionary is bound.
HostSheet #
host-sheet
Worksheet holding the dictionary
Signature:
Private Property Get HostSheet() As Worksheet
Held on the instance. Reaching it through dict.Data.Wksh cost two crossings
before any work, on every cell this class resolved.
Returns: Worksheet
RefreshVariableRange #
Rebuild the range holding the variable names
Signature:
Private Sub RefreshVariableRange()
One path. DataSheet.DataRange resolves the column with shouldExist:=True,
so a dictionary without a "variable name" column raises here, and it always
hands back at least one data row. The second hand-built path this routine
used to carry could never run.
Throws:
- ProjectError.ElementNotFound When the variable-name column is missing.
EnsureVariableRange #
Build the search range when it is missing
Signature:
Private Sub EnsureVariableRange()
EnsureNamesLoaded #
ensure-names-loaded
Read the variable-name column once
Signature:
Private Sub EnsureNamesLoaded()
One crossing for the whole column. Every Contains, RowIndex,
VariableNames and cell resolve is answered from this array afterwards.
ReloadHeaders #
reload-headers
Read the header row once
Signature:
Private Sub ReloadHeaders()
EnsureHeadersLoaded #
ensure-headers-loaded
Read the header row when it has not been read yet
Signature:
Private Function EnsureHeadersLoaded() As Boolean
Says whether it read the sheet. A snapshot built in this very call is already fresh, so the caller can skip both the cell check and the second read.
Returns: Boolean. True when the header row was read in this call.
HeaderColumn #
header-column
Find a column in the header snapshot
Signature:
Private Function HeaderColumn(ByVal colName As String) As Long
Whole string, case-insensitive, leftmost wins. That is the same rule
DataSheet.FindColumn applies for the arguments this class used to pass it
(strictSearch:=True, matchCase:=False).
Parameters:
colName: String. Column header to look for.
Returns: Long. The worksheet column, or 0 when the snapshot does not hold it.
HeaderStillReads #
header-still-reads
Check one header cell against the name it is expected to hold
Signature:
Private Function HeaderStillReads(ByVal columnNumber As Long, ByVal colName As String) As Boolean
One crossing, and it is what stops a stale index. A header renamed on the worksheet leaves the snapshot pointing at a column that now holds something else, and handing that index out would read the wrong column's value.
Parameters:
columnNumber: Long. The worksheet column to test.colName: String. The header it should hold.
Returns: Boolean. True when the cell still reads as colName.
ResolveColumnIndex #
Resolve a dictionary column to a worksheet column
Signature:
Private Function ResolveColumnIndex(ByVal colName As String, Optional ByVal required As Boolean = False) As Long
Answers from the header snapshot, checks the answer with one cell read, and reads the header row again when either step comes up short. The second read is what lets a column added after this object was built resolve.
Parameters:
colName: String. Column header to resolve.required: Optional Boolean. When True, a missing column raises. Defaults to False.
Returns: Long. The worksheet column, or 0 when it is missing and required is False.
Throws:
- ProjectError.InvalidArgument When colName is empty and required is True.
- ProjectError.ElementNotFound When the column is missing and required is True.
CellText #
cell-text
Read one cell value as text
Signature:
Private Function CellText(ByVal cellValue As Variant) As String
A dictionary cell can hold an error value (#N/A, #REF!) or a Null, and
CStr raises on both. Every read in this class goes through here.
The parameter is called cellValue because this module also holds a public
Value function. VBA renormalises every use of an identifier to whichever
spelling it saw last, across the whole project.
Parameters:
cellValue: Variant. The raw cell value.
Returns: String. The text, or an empty string when there is none.
Reading
RowIndex #
row-index
Find the worksheet row of one variable
Signature:
Private Function RowIndex(ByVal varName As String, Optional ByVal matchCase As Boolean = True) As Long
Answers 0 when the variable is absent, and every caller tests for 0.
A duplicated variable name answers with the FIRST row that holds it.
Range.Find started after the first cell and wrapped, so it used to answer
with the second. LLdictionary.UniqueVarNames makes the names unique during
preparation, so two equal names are a fault in the sheet either way.
Parameters:
varName: String. Variable to look for.matchCase: Optional Boolean. When True, the match is case-sensitive. Defaults to True.
Returns: Long. The worksheet row, or 0 when the variable is absent.
CellRangeInternal #
cell-range-internal
Resolve the cell holding one column of one variable
Signature:
Private Function CellRangeInternal(ByVal colName As String, _
ByVal varName As String, _
ByVal matchCase As Boolean) As Range
Parameters:
colName: String. Column header.varName: String. Variable name.matchCase: Boolean. When True, the variable match is case-sensitive.
Returns: Range. The cell, or Nothing when the row or the column is missing.
ReadColumnValue #
read-column-value
Read one column of one variable as text
Signature:
Private Function ReadColumnValue(ByVal varName As String, _
ByVal colName As String, _
ByVal matchCase As Boolean) As String
The single reader. Value, SheetName, ControlType and TableName are all
one line over this; the two argument orders those members expose are the only
thing that used to differ between them.
Parameters:
varName: String. Variable name.colName: String. Column header.matchCase: Boolean. When True, the variable match is case-sensitive.
Returns: String. The cell text, or an empty string.
Errors
ThrowError #
throw-error
Raise an error from this class
Signature:
Private Sub ThrowError(ByVal errNumb As Long, ByVal errorMessage As String)
Parameters:
errNumb: Long. The ProjectError value.errorMessage: String. The message.
Used in (30 file(s))
- AnalysisOutput.cls
- CrossTable.cls
- TableSpecs.cls
- LLExporter.cls
- LLImporter.cls
- LLdictionary.cls
- LLExport.cls
- LLSheets.cls
- FormulaCondition.cls
- Formulas.cls
- ValueOfFormula.cls
- EventLinelist.cls
- Linelist.cls
- LinelistSpecs.cls
- VarWriter.cls
- EventSetup.cls
- SetupErrors.cls
- ShowHide.cls
- MasterSetupHelpers.bas
- TestCrossTable.bas
- TestCrossTableFormula.bas
- TestSpatialTables.bas
- TestLLSheetsExtra.bas
- TestLLVariables.bas
- TestLLVariablesExtra.bas
- TestFormulaCondition.bas
- TestFormulas.bas
- TestValueOfFormula.bas
- TestEventLinelistSheets.bas
- TestVarWriter.bas