Skip to content
This repository has been archived by the owner on Feb 14, 2023. It is now read-only.

Commit

Permalink
document GenericItem#label= and GenericItem#category=
Browse files Browse the repository at this point in the history
refs #51

and add #modify method to update them in batch (or to override the
provider check)
  • Loading branch information
ccutrer committed Jan 9, 2023
1 parent bf7615c commit 5093fe3
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 14 deletions.
8 changes: 3 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,9 @@ here is a non-exhaustive list of significant departures from the original gem:
* {OpenHAB::DSL::Rules::BuilderDSL#on_load #on_load} supports delay
* Various Ephemeris methods on {ZonedDateTime}.
* {OpenHAB::DSL::Rules::BuilderDSL#dependencies} Rule dependencies
* A set of debounce/throttle guards for file-based rules: {OpenHAB::DSL::Rules::BuilderDSL#debounce_for debounce_for},
{OpenHAB::DSL::Rules::BuilderDSL#throttle_for throttle_for}, and
{OpenHAB::DSL::Rules::BuilderDSL#only_every only_every}
* And for UI rules: {OpenHAB::DSL.debounce_for debounce_for}, {OpenHAB::DSL.throttle_for throttle_for},
{OpenHAB::DSL.only_every only_every}
* A set of debounce/throttle guards for file-based rules: {OpenHAB::DSL::Rules::BuilderDSL#debounce_for debounce_for}, {OpenHAB::DSL::Rules::BuilderDSL#throttle_for throttle_for}, and {OpenHAB::DSL::Rules::BuilderDSL#only_every only_every}
* And for UI rules: {OpenHAB::DSL.debounce_for debounce_for}, {OpenHAB::DSL.throttle_for throttle_for}, {OpenHAB::DSL.only_every only_every}
* Explicitly document modifying item labels and categories (where possible), and notify openHAB of the change

### Bug Fixes

Expand Down
66 changes: 66 additions & 0 deletions lib/openhab/core/items/generic_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,72 @@ def format_type(type)

type.to_s
end

#
# Defers notifying openHAB of modifications to multiple attributes until the block is complete.
#
# @param force [true, false] force allowing modifications to file-based items.
# Normally a FrozenError is raised when attempting to modify file-based items, since
# they will then be out-of-sync with the definition on disk. Advanced users may do this
# knowingly and intentionally though, so an escape hatch is provided to allow runtime
# modifications.
# @yield
# @return [Object] the block's return value
#
# @example Modify label and tags for an item
# MySwitch.modify do
# MySwitch.label = "New Label"
# MySwitch.tag = [:labeled]
# end
#
def modify(force: false)
raise ArgumentError, "you must pass a block to modify" unless block_given?
return yield if instance_variable_defined?(:@modifying) && @modifying

begin
provider = self.provider
if provider && !provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
provider = nil
raise FrozenError, "Cannot modify item #{name} from provider #{provider.inspect}." unless force

logger.debug("Forcing modifications to non-managed item #{name}")
end
@modified = false
@modifying = true

r = yield

provider&.update(self) if @modified
r
ensure
@modifying = false
end
end

# @!attribute [rw] label
# The item's descriptive label.
# @return [String]
def label=(value)
modify do
next if label == value

@modified = true
set_label(value)
end
end

# @!attribute [rw] category
# The item's category.
# @return [String]
def category=(value)
modify do
value = value&.to_s
next if category == value

@modified = true
set_category(value)
end
end
end
end
end
Expand Down
11 changes: 6 additions & 5 deletions lib/openhab/core/items/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,14 @@ def ===(other)
# The item's name.
# @return [String]

# @!attribute [r] label
# The item's descriptive label.
# @return [String, nil]

# @!attribute [r] accepted_command_types
# @return [Array<Class>] An array of {Command}s that can be sent as commands to this item

# @!attribute [r] accepted_data_types
# @return [Array<Class>] An array of {State}s that can be sent as commands to this item

#
# The item's {#label} if one is defined, otherwise it's {#name}.
# The item's {GenericItem#label label} if one is defined, otherwise its {#name}.
#
# @return [String]
#
Expand Down Expand Up @@ -206,6 +202,11 @@ def inspect
"#{s}>"
end

# @return [org.openhab.core.common.registry.Provider]
def provider
Provider.registry.provider_for(self)
end

private

# Allows sub-classes to append additional details to the type in an inspect string
Expand Down
6 changes: 5 additions & 1 deletion lib/openhab/core/registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ class Registry
#
def provider_for(key)
elementReadLock.lock
return nil unless (element = identifierToElement[key])
if key.is_a?(org.openhab.core.common.registry.Identifiable)
element = key
else
return nil unless (element = identifierToElement[key])
end

elementToProvider[element]
ensure
Expand Down
3 changes: 0 additions & 3 deletions lib/openhab/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,6 @@ def only_every(interval, id: nil, &block)
# end # the states will be restored here
#
def store_states(*items)
items = items.flatten.map do |item|
item.respond_to?(:__getobj__) ? item.__getobj__ : item
end
states = Core::Items::StateStorage.from_items(*items)
if block_given?
yield
Expand Down
44 changes: 44 additions & 0 deletions spec/openhab/core/items/item_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,50 @@
expect(Switch1).not_to eq Switch3
end

describe "#label=" do
it "calls update on the provider" do
expect(LightSwitch.provider).to receive(:update)
LightSwitch.label = "Light Switch"
end

it "doesn't call update if no change was made" do
LightSwitch.label = "Light Switch"
expect(LightSwitch.provider).not_to receive(:update)
LightSwitch.label = "Light Switch"
end

it "raises an error if the item's provider doesn't support update" do
expect(LightSwitch.provider).not_to receive(:update)
allow(LightSwitch).to receive(:provider).and_return(Object.new)
expect { LightSwitch.label = "Light Switch" }.to raise_error(FrozenError)
end

it "ignores provider check if the item doesn't yet have a provider" do
expect(LightSwitch.provider).not_to receive(:update)
allow(LightSwitch).to receive(:provider).and_return(nil)
LightSwitch.label = "Light Switch"
expect(LightSwitch.label).to eql "Light Switch"
end
end

describe "#modify" do
it "batches multiple provider update calls" do
expect(LightSwitch.provider).to receive(:update).once
LightSwitch.modify do
LightSwitch.label = "Light Switch 1"
LightSwitch.label = "Light Switch 2"
end
end

it "doesn't call update if the item's provider doesn't support it and we're forced" do
expect(LightSwitch.provider).not_to receive(:update)
allow(LightSwitch).to receive(:provider).and_return(nil)
LightSwitch.modify(force: true) do
LightSwitch.label = "Light Switch"
end
end
end

describe "entity lookup" do
it "doesn't confuse a method call with an item" do
items.build { group_item "gGroup" }
Expand Down
6 changes: 6 additions & 0 deletions spec/openhab/core/items/registry_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@
expect(items).not_to include("SimmerTest")
expect(items["SimmerTest"]).to be_nil
end

describe "#provider" do
it "works" do
expect(SwitchTwo.provider).to be_a OpenHAB::Core::Items::Provider
end
end
end

0 comments on commit 5093fe3

Please sign in to comment.