openhab-jrubyscripting 5.0.0.rc9 → 5.0.0.rc11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/openhab/core/actions/audio.rb +47 -0
- data/lib/openhab/core/actions/ephemeris.rb +39 -0
- data/lib/openhab/core/actions/exec.rb +51 -0
- data/lib/openhab/core/actions/http.rb +80 -0
- data/lib/openhab/core/actions/ping.rb +30 -0
- data/lib/openhab/core/actions/transformation.rb +32 -0
- data/lib/openhab/core/actions/voice.rb +36 -0
- data/lib/openhab/core/actions.rb +23 -120
- data/lib/openhab/core/{events → dto}/item_channel_link.rb +1 -4
- data/lib/openhab/core/{events → dto}/thing.rb +10 -12
- data/lib/openhab/core/dto.rb +11 -0
- data/lib/openhab/core/entity_lookup.rb +1 -1
- data/lib/openhab/core/events/abstract_event.rb +1 -0
- data/lib/openhab/core/events/abstract_item_registry_event.rb +36 -0
- data/lib/openhab/core/events/abstract_thing_registry_event.rb +40 -0
- data/lib/openhab/core/events/item_command_event.rb +1 -1
- data/lib/openhab/core/events/item_state_changed_event.rb +6 -6
- data/lib/openhab/core/events/item_state_event.rb +6 -6
- data/lib/openhab/core/events/thing_status_info_event.rb +8 -6
- data/lib/openhab/core/items/generic_item.rb +2 -1
- data/lib/openhab/core/items/persistence.rb +52 -18
- data/lib/openhab/core/items/player_item.rb +1 -1
- data/lib/openhab/core/items/proxy.rb +20 -14
- data/lib/openhab/core/items/registry.rb +2 -0
- data/lib/openhab/core/items.rb +3 -3
- data/lib/openhab/core/profile_factory.rb +3 -1
- data/lib/openhab/core/proxy.rb +125 -0
- data/lib/openhab/core/things/links/provider.rb +1 -1
- data/lib/openhab/core/things/proxy.rb +8 -0
- data/lib/openhab/core/types/date_time_type.rb +2 -1
- data/lib/openhab/core/types/decimal_type.rb +1 -1
- data/lib/openhab/core/types/un_def_type.rb +2 -2
- data/lib/openhab/core/value_cache.rb +1 -1
- data/lib/openhab/core_ext/ephemeris.rb +53 -0
- data/lib/openhab/core_ext/java/class.rb +1 -1
- data/lib/openhab/core_ext/java/duration.rb +25 -1
- data/lib/openhab/core_ext/java/local_date.rb +2 -0
- data/lib/openhab/core_ext/java/month_day.rb +2 -0
- data/lib/openhab/core_ext/java/zoned_date_time.rb +85 -0
- data/lib/openhab/core_ext/ruby/date.rb +2 -0
- data/lib/openhab/core_ext/ruby/date_time.rb +1 -0
- data/lib/openhab/core_ext/ruby/time.rb +1 -0
- data/lib/openhab/dsl/debouncer.rb +259 -0
- data/lib/openhab/dsl/items/builder.rb +4 -2
- data/lib/openhab/dsl/items/timed_command.rb +31 -13
- data/lib/openhab/dsl/rules/automation_rule.rb +28 -21
- data/lib/openhab/dsl/rules/builder.rb +357 -37
- data/lib/openhab/dsl/rules/guard.rb +12 -54
- data/lib/openhab/dsl/rules/name_inference.rb +11 -0
- data/lib/openhab/dsl/rules/property.rb +3 -4
- data/lib/openhab/dsl/rules/terse.rb +4 -1
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +5 -6
- data/lib/openhab/dsl/rules/triggers/cron/cron.rb +1 -0
- data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +19 -31
- data/lib/openhab/dsl/rules/triggers/watch/watch.rb +1 -0
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +22 -30
- data/lib/openhab/dsl/things/builder.rb +1 -1
- data/lib/openhab/dsl/thread_local.rb +1 -0
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +224 -3
- data/lib/openhab/rspec/hooks.rb +5 -2
- data/lib/openhab/rspec/karaf.rb +7 -0
- data/lib/openhab/rspec/mocks/instance_method_stasher.rb +22 -0
- data/lib/openhab/rspec/mocks/space.rb +23 -0
- data/lib/openhab/rspec/openhab/core/actions.rb +16 -4
- data/lib/openhab/rspec/openhab/core/items/proxy.rb +1 -13
- data/lib/openhab/rspec/suspend_rules.rb +1 -14
- data/lib/openhab/yard/base_helper.rb +19 -0
- data/lib/openhab/yard/code_objects/group_object.rb +9 -3
- data/lib/openhab/yard/coderay.rb +17 -0
- data/lib/openhab/yard/handlers/jruby/base.rb +10 -1
- data/lib/openhab/yard/handlers/jruby/java_import_handler.rb +3 -0
- data/lib/openhab/yard/html_helper.rb +49 -15
- data/lib/openhab/yard/markdown_helper.rb +135 -0
- data/lib/openhab/yard.rb +6 -0
- metadata +36 -4
data/lib/openhab/dsl.rb
CHANGED
@@ -37,6 +37,13 @@ module OpenHAB
|
|
37
37
|
public_class_method(*mod.private_instance_methods)
|
38
38
|
end
|
39
39
|
|
40
|
+
class << self
|
41
|
+
# @!visibility private
|
42
|
+
attr_reader :debouncers
|
43
|
+
end
|
44
|
+
|
45
|
+
@debouncers = java.util.concurrent.ConcurrentHashMap.new
|
46
|
+
|
40
47
|
module_function
|
41
48
|
|
42
49
|
# @!group Rule Creation
|
@@ -53,6 +60,8 @@ module OpenHAB
|
|
53
60
|
|
54
61
|
# @!group Rule Support
|
55
62
|
|
63
|
+
# rubocop:disable Layout/LineLength
|
64
|
+
|
56
65
|
#
|
57
66
|
# Defines a new profile that can be applied to item channel links.
|
58
67
|
#
|
@@ -79,8 +88,8 @@ module OpenHAB
|
|
79
88
|
# @see org.openhab.thing.Profile
|
80
89
|
# @see org.openhab.thing.StateProfile
|
81
90
|
#
|
82
|
-
# @example
|
83
|
-
# profile(:veto_closing_shades) do |event, item:, command
|
91
|
+
# @example Vetoing a command
|
92
|
+
# profile(:veto_closing_shades) do |event, item:, command:|
|
84
93
|
# next false if command&.down?
|
85
94
|
#
|
86
95
|
# true
|
@@ -94,9 +103,37 @@ module OpenHAB
|
|
94
103
|
# # can also be referenced from an `.items` file:
|
95
104
|
# # Rollershutter MyShade { channel="thing:rollershutter"[profile="ruby:veto_closing_shades"] }
|
96
105
|
#
|
106
|
+
# @example Overriding units from a binding
|
107
|
+
# profile(:set_uom) do |event, configuration:, state:, command:|
|
108
|
+
# unless configuration["unit"]
|
109
|
+
# logger.warn("Unit configuration not provided for set_uom profile")
|
110
|
+
# next true
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# case event
|
114
|
+
# when :state_from_handler
|
115
|
+
# next true unless state.is_a?(DecimalType) || state.is_a?(QuantityType) # what is it then?!
|
116
|
+
#
|
117
|
+
# state = state.to_d if state.is_a?(QuantityType) # ignore the units if QuantityType was given
|
118
|
+
# callback.send_update(state | configuration["unit"])
|
119
|
+
# false
|
120
|
+
# when :command_from_item
|
121
|
+
# # strip the unit from the command, as the binding likely can't handle it
|
122
|
+
# next true unless command.is_a?(QuantityType)
|
123
|
+
#
|
124
|
+
# callback.send_command(DecimalType.new(command.to_d))
|
125
|
+
# false
|
126
|
+
# else
|
127
|
+
# true # pass other events through as normal
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
# # can also be referenced from an `.items` file:
|
131
|
+
# # Number:Temperature MyTempWithNonUnitValueFromBinding "I prefer Celsius [%d °C]" { channel="something_that_returns_F"[profile="ruby:set_uom", unit="°F"] }
|
132
|
+
#
|
97
133
|
def profile(id, &block)
|
98
134
|
raise ArgumentError, "Block is required" unless block
|
99
135
|
|
136
|
+
id = id.to_s
|
100
137
|
uid = org.openhab.core.thing.profiles.ProfileTypeUID.new("ruby", id)
|
101
138
|
|
102
139
|
ThreadLocal.thread_local(openhab_rule_type: "profile", openhab_rule_uid: id) do
|
@@ -104,6 +141,8 @@ module OpenHAB
|
|
104
141
|
end
|
105
142
|
end
|
106
143
|
|
144
|
+
# rubocop:enable Layout/LineLength
|
145
|
+
|
107
146
|
# @!group Object Access
|
108
147
|
|
109
148
|
#
|
@@ -335,6 +374,133 @@ module OpenHAB
|
|
335
374
|
Range.new(start, finish, range.exclude_end?)
|
336
375
|
end
|
337
376
|
|
377
|
+
#
|
378
|
+
# Limits the frequency of calls to the given block within a given amount of time.
|
379
|
+
#
|
380
|
+
# It can be useful to throttle certain actions even when a rule is triggered too often.
|
381
|
+
# This can be used to debounce triggers in a UI rule.
|
382
|
+
#
|
383
|
+
# @param (see Debouncer#initialize)
|
384
|
+
# @param [Object] id ID to associate with this debouncer.
|
385
|
+
# @param [Block] block The block to be debounced.
|
386
|
+
#
|
387
|
+
# @return [void]
|
388
|
+
#
|
389
|
+
# @example Run at most once per second even when being called more frequently
|
390
|
+
# (1..100).each do
|
391
|
+
# debounce for: 1.second do
|
392
|
+
# logger.info "This will not be logged more frequently than every 1 second"
|
393
|
+
# end
|
394
|
+
# sleep 0.1
|
395
|
+
# end
|
396
|
+
#
|
397
|
+
# @see Debouncer Debouncer class
|
398
|
+
# @see Rules::BuilderDSL#debounce debounce rule guard
|
399
|
+
#
|
400
|
+
# @!visibility private
|
401
|
+
def debounce(for:, leading: false, idle_time: nil, id: nil, &block)
|
402
|
+
interval = binding.local_variable_get(:for)
|
403
|
+
id ||= block.source_location
|
404
|
+
DSL.debouncers.compute(id) do |_key, debouncer|
|
405
|
+
debouncer ||= Debouncer.new(for: interval, leading: leading, idle_time: idle_time)
|
406
|
+
debouncer.call(&block)
|
407
|
+
debouncer
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
#
|
412
|
+
# Waits until calls to this method have stopped firing for a period of time
|
413
|
+
# before executing the block.
|
414
|
+
#
|
415
|
+
# This method acts as a guard for the given block to ensure that it doesn't get executed
|
416
|
+
# too frequently. The debounce_for method can be called as frequently as possible.
|
417
|
+
# The given block, however, will only be executed once the `debounce_time` has passed
|
418
|
+
# since the last call to debounce_for.
|
419
|
+
#
|
420
|
+
# This method can be used from within a UI rule as well as from a file-based rule.
|
421
|
+
#
|
422
|
+
# @param (see Rules::BuilderDSL#debounce_for)
|
423
|
+
# @param [Object] id ID to associate with this call.
|
424
|
+
# @param [Block] block The block to be debounced.
|
425
|
+
#
|
426
|
+
# @return [void]
|
427
|
+
#
|
428
|
+
# @example Run a block of code only after an item has stopped changing
|
429
|
+
# # This can be placed inside a UI rule with an Item Change trigger for
|
430
|
+
# # a Door contact sensor.
|
431
|
+
# # If the door state has stopped changing state for 10 minutes,
|
432
|
+
# # execute the block.
|
433
|
+
# debounce_for(10.minutes) do
|
434
|
+
# if DoorState.open?
|
435
|
+
# Voice.say("The door has been left open!")
|
436
|
+
# end
|
437
|
+
# end
|
438
|
+
#
|
439
|
+
# @see Rules::BuilderDSL#debounce_for Rule builder's debounce_for for a detailed description
|
440
|
+
#
|
441
|
+
def debounce_for(debounce_time, id: nil, &block)
|
442
|
+
idle_time = debounce_time.is_a?(Range) ? debounce_time.begin : debounce_time
|
443
|
+
debounce(for: debounce_time, idle_time: idle_time, id: id, &block)
|
444
|
+
end
|
445
|
+
|
446
|
+
#
|
447
|
+
# Rate-limits block executions by delaying calls and only executing the last
|
448
|
+
# call within the given duration.
|
449
|
+
#
|
450
|
+
# When throttle_for is called, it will hold from executing the block and start
|
451
|
+
# a fixed timer for the given duration. Should more calls occur during
|
452
|
+
# this time, keep holding and once the wait time is over, execute the block.
|
453
|
+
#
|
454
|
+
# {throttle_for} will execute the block after it had waited for the given duration,
|
455
|
+
# regardless of how frequently `throttle_for` was called.
|
456
|
+
# In contrast, {debounce_for} will wait until there is a minimum interval
|
457
|
+
# between two triggers.
|
458
|
+
#
|
459
|
+
# {throttle_for} is ideal in situations where regular status updates need to be made
|
460
|
+
# for frequently changing values. It is also useful when a rule responds to triggers
|
461
|
+
# from multiple related items that are updated at around the same time. Instead of
|
462
|
+
# executing the rule multiple times, {throttle_for} will wait for a pre-set amount
|
463
|
+
# of time since the first group of triggers occurred before executing the rule.
|
464
|
+
#
|
465
|
+
# @param (see Rules::BuilderDSL#throttle_for)
|
466
|
+
# @param [Object] id ID to associate with this call.
|
467
|
+
# @param [Block] block The block to be throttled.
|
468
|
+
#
|
469
|
+
# @return [void]
|
470
|
+
#
|
471
|
+
# @see Rules::BuilderDSL#debounce_for Rule builder's debounce_for for a detailed description
|
472
|
+
# @see Rules::BuilderDSL#throttle_for
|
473
|
+
#
|
474
|
+
def throttle_for(duration, id: nil, &block)
|
475
|
+
debounce(for: duration, id: id, &block)
|
476
|
+
end
|
477
|
+
|
478
|
+
#
|
479
|
+
# Limit how often the given block executes to the specified interval.
|
480
|
+
#
|
481
|
+
# {only_every} will execute the given block but prevents further executions
|
482
|
+
# until the given interval has passed. In contrast, {throttle_for} will not
|
483
|
+
# execute the block immediately, and will wait until the end of the interval.
|
484
|
+
#
|
485
|
+
# @param (see Rules::BuilderDSL#only_every)
|
486
|
+
# @param [Object] id ID to associate with this call.
|
487
|
+
# @param [Block] block The block to be throttled.
|
488
|
+
#
|
489
|
+
# @return [void]
|
490
|
+
#
|
491
|
+
# @example Prevent door bell from ringing repeatedly
|
492
|
+
# # This can be called from a UI rule.
|
493
|
+
# # For file based rule, use the `only_every` rule guard
|
494
|
+
# only_every(30.seconds) do { Audio.play_sound("doorbell.mp3") }
|
495
|
+
#
|
496
|
+
# @see Rules::BuilderDSL#debounce_for Rule builder's debounce_for for a detailed description
|
497
|
+
# @see Rules::BuilderDSL#only_every
|
498
|
+
#
|
499
|
+
def only_every(interval, id: nil, &block)
|
500
|
+
interval = 1.send(interval) if %i[second minute hour day].include?(interval)
|
501
|
+
debounce(for: interval, leading: true, id: id, &block)
|
502
|
+
end
|
503
|
+
|
338
504
|
#
|
339
505
|
# Store states of supplied items
|
340
506
|
#
|
@@ -624,7 +790,7 @@ module OpenHAB
|
|
624
790
|
#
|
625
791
|
# @overload provider!(things: nil, items: nil, metadata: nil, links: nil, **metadata_items)
|
626
792
|
#
|
627
|
-
# @param [Core::Provider, org.openhab.core.registry.
|
793
|
+
# @param [Core::Provider, org.openhab.core.common.registry.ManagedProvider, :persistent, :transient, Proc] providers
|
628
794
|
# An explicit provider to use. If it's a {Core::Provider}, the type will be inferred automatically.
|
629
795
|
# Otherwise it's applied to all types.
|
630
796
|
# @param [Hash] providers_by_type
|
@@ -703,6 +869,61 @@ module OpenHAB
|
|
703
869
|
old_providers
|
704
870
|
end
|
705
871
|
|
872
|
+
#
|
873
|
+
# @see CoreExt::Ephemeris
|
874
|
+
#
|
875
|
+
# @overload holiday_file(file)
|
876
|
+
#
|
877
|
+
# Sets a thread local variable to use a specific holiday file
|
878
|
+
# for {CoreExt::Ephemeris ephemeris calls} inside the block.
|
879
|
+
#
|
880
|
+
# @param [String, nil] file Path to a file defining holidays;
|
881
|
+
# `nil` to reset to default.
|
882
|
+
# @yield [] Block executed in context of the supplied holiday file
|
883
|
+
# @return [Object] The return value from the block.
|
884
|
+
#
|
885
|
+
# @example Set a specific holiday configuration file temporarily
|
886
|
+
# holiday_file("/home/cody/holidays.xml") do
|
887
|
+
# Time.now.next_holiday
|
888
|
+
# end
|
889
|
+
#
|
890
|
+
# @see holiday_file!
|
891
|
+
#
|
892
|
+
# @overload holiday_file
|
893
|
+
#
|
894
|
+
# Returns the current thread local value for the holiday file.
|
895
|
+
#
|
896
|
+
# @return [String, nil] the current holiday file
|
897
|
+
#
|
898
|
+
def holiday_file(*args)
|
899
|
+
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)" if args.length > 1
|
900
|
+
|
901
|
+
old = Thread.current[:openhab_holiday_file]
|
902
|
+
return old if args.empty?
|
903
|
+
|
904
|
+
holiday_file!(args.first)
|
905
|
+
yield
|
906
|
+
ensure
|
907
|
+
holiday_file!(old)
|
908
|
+
end
|
909
|
+
|
910
|
+
#
|
911
|
+
# Sets a thread local variable to set the default holiday file.
|
912
|
+
#
|
913
|
+
# @see https://github.com/svendiedrichsen/jollyday/tree/master/src/main/resources/holidays Example data files from the source
|
914
|
+
#
|
915
|
+
# @example
|
916
|
+
# holiday_file!("/home/cody/holidays.xml")
|
917
|
+
# Time.now.next_holiday
|
918
|
+
#
|
919
|
+
# @param [String, nil] file Path to a file defining holidays;
|
920
|
+
# `nil` to reset to default.
|
921
|
+
# @return [Symbol, nil] the new holiday file
|
922
|
+
#
|
923
|
+
def holiday_file!(file = nil)
|
924
|
+
Thread.current[:openhab_holiday_file] = file
|
925
|
+
end
|
926
|
+
|
706
927
|
# @!visibility private
|
707
928
|
def try_parse_time_like(string)
|
708
929
|
return string unless string.is_a?(String)
|
data/lib/openhab/rspec/hooks.rb
CHANGED
@@ -32,6 +32,11 @@ module OpenHAB
|
|
32
32
|
config.include ExampleGroup
|
33
33
|
|
34
34
|
config.before(:suite) do
|
35
|
+
if config.mock_framework.framework_name == :rspec
|
36
|
+
require_relative "mocks/instance_method_stasher"
|
37
|
+
require_relative "mocks/space"
|
38
|
+
end
|
39
|
+
|
35
40
|
Helpers.autorequires unless Configuration.private_confdir
|
36
41
|
Helpers.send(:set_up_autoupdates)
|
37
42
|
Helpers.load_transforms
|
@@ -86,8 +91,6 @@ module OpenHAB
|
|
86
91
|
end
|
87
92
|
|
88
93
|
config.after do
|
89
|
-
Core::Items::Proxy.reset_cache
|
90
|
-
Core::Things::Proxy.reset_cache
|
91
94
|
@profile_factory.unregister
|
92
95
|
timers.cancel_all
|
93
96
|
# timers and rules have already been canceled, so we can safely just
|
data/lib/openhab/rspec/karaf.rb
CHANGED
@@ -280,6 +280,13 @@ module OpenHAB
|
|
280
280
|
props = cfg.properties || java.util.Hashtable.new
|
281
281
|
props.put("default", "default")
|
282
282
|
cfg.update(props)
|
283
|
+
|
284
|
+
# configure ephemeris with basic values
|
285
|
+
cfg = ca.get_configuration("org.openhab.ephemeris", nil)
|
286
|
+
props = cfg.properties || java.util.Hashtable.new
|
287
|
+
props.put("country", "us")
|
288
|
+
props.put("dayset-weekend", %w[SATURDAY SUNDAY])
|
289
|
+
cfg.update(props)
|
283
290
|
end
|
284
291
|
wait_for_service("org.openhab.core.automation.RuleManager") do |re|
|
285
292
|
require_relative "mocks/synchronous_executor"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module RSpec
|
5
|
+
module Mocks
|
6
|
+
module InstanceMethodStasher
|
7
|
+
::RSpec::Mocks::InstanceMethodStasher.prepend(self)
|
8
|
+
|
9
|
+
# Disable "singleton on non-persistent Java type"
|
10
|
+
# it doesn't matter during specs
|
11
|
+
def initialize(*)
|
12
|
+
original_verbose = $VERBOSE
|
13
|
+
$VERBOSE = nil
|
14
|
+
|
15
|
+
super
|
16
|
+
ensure
|
17
|
+
$VERBOSE = original_verbose
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module RSpec
|
5
|
+
module Mocks
|
6
|
+
module Space
|
7
|
+
::RSpec::Mocks::Space.prepend(self)
|
8
|
+
|
9
|
+
#
|
10
|
+
# When setting expectations on {Items::Proxy proxies}, set them against the item
|
11
|
+
# themselves, so that it will catch calls against `self` from within the instance.
|
12
|
+
#
|
13
|
+
def proxy_for(object)
|
14
|
+
return super unless ::RSpec.current_example&.example_group&.consistent_proxies?
|
15
|
+
|
16
|
+
object = object.__getobj__ if object.is_a?(Core::Items::Proxy)
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -12,12 +12,24 @@ module OpenHAB
|
|
12
12
|
logger.debug("notify: #{msg}")
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
class Voice
|
16
|
+
class << self
|
17
|
+
def say(text, voice: nil, sink: nil, volume: nil)
|
18
|
+
logger.debug("say: #{text}")
|
19
|
+
end
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
|
-
|
20
|
-
|
23
|
+
class Audio
|
24
|
+
class << self
|
25
|
+
def play_sound(filename, sink: nil, volume: nil)
|
26
|
+
logger.debug("play_sound: #{filename}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def play_stream(url, sink: nil)
|
30
|
+
logger.debug("play_stream: #{url}")
|
31
|
+
end
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
35
|
# rubocop:enable Lint/UnusedMethodArgument
|
@@ -4,21 +4,9 @@ module OpenHAB
|
|
4
4
|
module Core
|
5
5
|
module Items
|
6
6
|
class Proxy
|
7
|
-
@proxies = {}
|
8
|
-
|
9
7
|
class << self
|
10
|
-
# ensure each item only has a single proxy, so that
|
11
|
-
# expect(item).to receive(:method) works
|
12
|
-
def new(item)
|
13
|
-
return super unless defined?(::RSpec) && ::RSpec.current_example&.example_group&.consistent_proxies?
|
14
|
-
|
15
|
-
@proxies.fetch(item.name) do
|
16
|
-
@proxies[item.name] = super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
8
|
def reset_cache
|
21
|
-
@proxies
|
9
|
+
@proxies.clear
|
22
10
|
end
|
23
11
|
end
|
24
12
|
end
|
@@ -12,20 +12,7 @@ module OpenHAB
|
|
12
12
|
logger.trace("Skipping execution of #{uid} because rules are suspended.")
|
13
13
|
return
|
14
14
|
end
|
15
|
-
|
16
|
-
# super
|
17
|
-
::OpenHAB::DSL::ThreadLocal.thread_local(**@thread_locals) do
|
18
|
-
logger.trace { "Execute called with mod (#{mod&.to_string}) and inputs (#{inputs.inspect})" }
|
19
|
-
logger.trace { "Event details #{inputs["event"].inspect}" } if inputs&.key?("event")
|
20
|
-
trigger_conditions(inputs).process(mod: mod, inputs: inputs) do
|
21
|
-
event = extract_event(inputs)
|
22
|
-
process_queue(create_queue(event), mod, event)
|
23
|
-
end
|
24
|
-
rescue Exception => e
|
25
|
-
raise if defined?(::RSpec) && ::RSpec.current_example.example_group.propagate_exceptions?
|
26
|
-
|
27
|
-
@run_context.send(:logger).log_exception(e)
|
28
|
-
end
|
15
|
+
execute!(mod, inputs)
|
29
16
|
end
|
30
17
|
end
|
31
18
|
# private_constant :AutomationRule
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenHAB
|
4
|
+
module YARD
|
5
|
+
# @!visibility private
|
6
|
+
module BaseHelper
|
7
|
+
def link_object(obj, title = nil, *)
|
8
|
+
::YARD::Handlers::JRuby::Base.infer_java_class(obj) if obj.is_a?(String)
|
9
|
+
obj = ::YARD::Registry.resolve(object, obj, true, true) if obj.is_a?(String)
|
10
|
+
if obj.is_a?(::YARD::CodeObjects::Java::Base) && (see = obj.docstring.tag(:see))
|
11
|
+
# link to the first see tag
|
12
|
+
return linkify(see.name, title&.to_s || see.text)
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -4,13 +4,19 @@ module OpenHAB
|
|
4
4
|
module YARD
|
5
5
|
module CodeObjects
|
6
6
|
class GroupObject < ::YARD::CodeObjects::Base
|
7
|
+
attr_reader :full_name
|
8
|
+
|
9
|
+
def initialize(namespace, name)
|
10
|
+
@full_name = name
|
11
|
+
name = name.delete(%(.?"')).tr(" ", "-")
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
7
15
|
def path
|
8
16
|
"group#{sep}#{super}"
|
9
17
|
end
|
10
18
|
|
11
|
-
|
12
|
-
name
|
13
|
-
end
|
19
|
+
alias_method :to_s, :full_name
|
14
20
|
end
|
15
21
|
end
|
16
22
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "coderay"
|
4
|
+
|
5
|
+
module OpenHAB
|
6
|
+
module YARD
|
7
|
+
module CodeRay
|
8
|
+
module HtmlHelper
|
9
|
+
::CodeRay::Scanners.list.each do |scanner|
|
10
|
+
define_method("html_syntax_highlight_#{scanner}") do |source|
|
11
|
+
::CodeRay.scan(source, scanner).html
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -7,9 +7,18 @@ module YARD
|
|
7
7
|
class << self
|
8
8
|
def infer_java_class(klass, inferred_type = nil, comments = nil, statement = nil)
|
9
9
|
components = klass.split(".")
|
10
|
+
components.pop if components.last == "freeze"
|
11
|
+
|
10
12
|
class_first_char = components.last[0]
|
11
13
|
is_field = components.last == components.last.upcase
|
12
|
-
|
14
|
+
container_first_char = components[-2]&.[](0)
|
15
|
+
is_method = container_first_char &&
|
16
|
+
class_first_char != class_first_char.upcase &&
|
17
|
+
container_first_char == container_first_char.upcase
|
18
|
+
is_package = !is_method && !is_field && class_first_char != class_first_char.upcase
|
19
|
+
|
20
|
+
# methods aren't supported right now
|
21
|
+
return if is_method
|
13
22
|
|
14
23
|
javadocs = YARD::Config.options.dig(:jruby, "javadocs") || {}
|
15
24
|
|
@@ -14,6 +14,9 @@ module YARD
|
|
14
14
|
obj = infer_java_class(klass)
|
15
15
|
next unless obj
|
16
16
|
|
17
|
+
# don't overwrite an already-extant object with the same name
|
18
|
+
next if ::YARD::Registry.at("#{namespace.path}::#{obj.simple_name}")
|
19
|
+
|
17
20
|
# then we create a new constant in the current namespace
|
18
21
|
register CodeObjects::ConstantObject.new(namespace, obj.simple_name) { |o|
|
19
22
|
o.source = statement
|
@@ -1,17 +1,62 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "nokogiri"
|
4
|
+
|
3
5
|
module OpenHAB
|
4
6
|
module YARD
|
5
7
|
# @!visibility private
|
6
8
|
module HtmlHelper
|
9
|
+
def base_url
|
10
|
+
if serializer.is_a?(::YARD::Server::DocServerSerializer)
|
11
|
+
abs_url(base_path(router.docs_prefix), "")
|
12
|
+
else
|
13
|
+
u = url_for("")
|
14
|
+
u = "#{u}/" if !u.empty? && u[-1] != "/"
|
15
|
+
u
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def url_for_search_index
|
20
|
+
if serializer.is_a?(::YARD::Server::DocServerSerializer)
|
21
|
+
url_for_list("index")
|
22
|
+
else
|
23
|
+
url_for("index.json")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
7
27
|
def html_markup_markdown(text)
|
8
|
-
result = super
|
28
|
+
result = super(text)
|
9
29
|
|
30
|
+
html = Nokogiri::HTML5.fragment(result)
|
10
31
|
# re-link files in docs/*.md. They're written so they work on github without any
|
11
32
|
# processing
|
12
|
-
|
13
|
-
|
14
|
-
|
33
|
+
unless serializer.is_a?(::YARD::Server::DocServerSerializer)
|
34
|
+
html.css("a[href!='']").each do |link|
|
35
|
+
uri = URI.parse(link["href"])
|
36
|
+
next unless uri.relative? && File.extname(uri.path) == ".md"
|
37
|
+
|
38
|
+
basename = File.basename(uri.path, ".md")
|
39
|
+
uri.path = "file.#{basename}.html"
|
40
|
+
link["href"] = uri.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# wtf commonmarker, you don't generate anchors?!
|
45
|
+
html.css("h1, h2, h3, h4, h5, h6").each do |header|
|
46
|
+
next if header["id"]
|
47
|
+
|
48
|
+
id = header.text.strip.downcase.delete(%(.?"')).tr(" ", "-")
|
49
|
+
header["id"] = id
|
50
|
+
header.prepend_child(%(<a href="##{id}" class="header-anchor">#</a>))
|
51
|
+
end
|
52
|
+
|
53
|
+
html.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def link_url(url, title = nil, params = {})
|
57
|
+
params.merge!(@link_attrs) if defined?(@link_attrs) && @link_attrs
|
58
|
+
params[:class] = params.delete(:classes).join(" ") if params[:classes]
|
59
|
+
super
|
15
60
|
end
|
16
61
|
|
17
62
|
# have to completely replace this method. only change is the regex splitting
|
@@ -28,17 +73,6 @@ module OpenHAB
|
|
28
73
|
list.empty? ? "" : (brackets ? "(#{list.join(", ")})" : list.join(", "))
|
29
74
|
end
|
30
75
|
# rubocop:enable Style/NestedTernaryOperator, Style/StringConcatenation, Style/TernaryParentheses
|
31
|
-
|
32
|
-
def link_object(obj, title = nil, *)
|
33
|
-
::YARD::Handlers::JRuby::Base.infer_java_class(obj) if obj.is_a?(String)
|
34
|
-
obj = ::YARD::Registry.resolve(object, obj, true, true) if obj.is_a?(String)
|
35
|
-
if obj.is_a?(::YARD::CodeObjects::Java::Base) && (see = obj.docstring.tag(:see))
|
36
|
-
# link to the first see tag
|
37
|
-
return linkify(see.name, title&.to_s || see.text)
|
38
|
-
end
|
39
|
-
|
40
|
-
super
|
41
|
-
end
|
42
76
|
end
|
43
77
|
end
|
44
78
|
end
|