]> git.basschouten.com Git - openhab-addons.git/commitdiff
[jrubyscripting] Update README.md (#14798)
authorjimtng <2554958+jimtng@users.noreply.github.com>
Fri, 14 Apr 2023 06:09:51 +0000 (16:09 +1000)
committerGitHub <noreply@github.com>
Fri, 14 Apr 2023 06:09:51 +0000 (08:09 +0200)
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
bundles/org.openhab.automation.jrubyscripting/README.md

index 78711efe6e2394b1a72baf658c3e31e325e28150..d689fd83be94f7dd0fb78ebc957e6caea73236ca 100644 (file)
@@ -1,7 +1,7 @@
 <!-- This file is auto-generated by YARD from https://github.com/openhab/openhab-jruby/blob/main/USAGE.md; please do not edit directly -->
 <!-- To regenerate, run `bin/yard display -f markdown -o https://openhab.github.io/openhab-jruby/5.0 file:USAGE.md` -->
 
-# JRuby Scripting <!-- omit from toc -->
+# JRuby Scripting
 
 This add-on provides [JRuby](https://www.jruby.org/) scripting language for automation rules.
 Also included is [openhab-scripting](https://openhab.github.io/openhab-jruby/), a fairly high-level Ruby gem to support automation in openHAB.
@@ -33,8 +33,11 @@ If you're new to Ruby, you may want to check out [Ruby Basics](https://openhab.g
   - [Cache](#cache)
   - [Time](#time)
   - [Ephemeris](#ephemeris)
+  - [Rules, Scripts, and Scenes](#rules-scripts-and-scenes)
   - [Gems](#gems)
   - [Shared Code](#shared-code)
+  - [Transformations](#transformations)
+  - [Profile](#profile)
 - [File Based Rules](#file-based-rules)
   - [Basic Rule Structure](#basic-rule-structure)
   - [Rule Triggers](#rule-triggers)
@@ -54,11 +57,9 @@ If you're new to Ruby, you may want to check out [Ruby Basics](https://openhab.g
     - [Triggered Execution Block](#triggered-execution-block)
     - [Delay Execution Block](#delay-execution-block)
   - [Terse Rules](#terse-rules)
-  - [Rule Manipulations](#rule-manipulations)
   - [Early Exit From a Rule](#early-exit-from-a-rule)
   - [Dynamic Generation of Rules](#dynamic-generation-of-rules)
   - [Hooks](#hooks)
-  - [Transformations](#transformations)
 - [Calling Java From JRuby](#calling-java-from-jruby)
 
 Additional [example rules are available](https://openhab.github.io/openhab-jruby/5.0/file.examples.html), as well as examples of [conversions from DSL and Python rules](https://openhab.github.io/openhab-jruby/5.0/file.conversions.html).
@@ -71,7 +72,7 @@ Additional [example rules are available](https://openhab.github.io/openhab-jruby
 - Rich ecosystem of tools, including things like Rubocop to help developers write clean code and RSpec to test the libraries.
 - Ruby is really good at letting one express intent and create a DSL to make that expression easier.
 
-### Design points <!-- omit from toc -->
+### Design points
 
 - Create an intuitive method of defining rules and automation
   - Rule language should "flow" in a way that you can read the rules out loud
@@ -87,12 +88,12 @@ Additional [example rules are available](https://openhab.github.io/openhab-jruby
 
 ## Installation
 
-### Prerequisites <!-- omit from toc -->
+### Prerequisites
 
 1. openHAB 3.4+
 1. The JRuby Scripting Language Addon
 
-### From the User Interface <!-- omit from toc -->
+### From the User Interface
 
 1. Go to `Settings -> Add-ons -> Automation` and install the jrubyscripting automation addon
    following the [openHAB instructions](https://www.openhab.org/docs/configuration/addons.html).
@@ -101,7 +102,7 @@ Additional [example rules are available](https://openhab.github.io/openhab-jruby
    - **Ruby Gems**: `openhab-scripting=~>5.0.0`
    - **Require Scripts**: `openhab/dsl` (not required, but recommended)
 
-### Using Files <!-- omit from toc -->
+### Using Files
 
 1. Edit `<OPENHAB_CONF>/services/addons.cfg` and ensure that `jrubyscripting` is included in
    an uncommented `automation=` list of automations to install.
@@ -125,16 +126,16 @@ This allows the use of [items](https://openhab.github.io/openhab-jruby/5.0/OpenH
 This functionality can be disabled for users who prefer to manage their own gems and `require`s via the add-on configuration options.
 Simply change the `gems` and `require` configuration settings.
 
-| Parameter             | Description                                                                                                |
-| --------------------- | ---------------------------------------------------------------------------------------------------------- |
+| Parameter             | Description                                                                                              |
+| --------------------- | -------------------------------------------------------------------------------------------------------- |
 | `gem_home`            | The path to store Ruby Gems. <br/><br/>Default: `$OPENHAB_CONF/automation/ruby/.gem/RUBY_ENGINE_VERSION` |
-| `gems`                | A list of gems to install. <br/><br/>Default: `openhab-scripting=~>5.0.0`                                  |
-| `check_update`        | Check for updated version of `gems` on start up or settings change. <br/><br/>Default: `true`              |
-| `require`             | List of scripts to be required automatically. <br/><br/>Default: `openhab/dsl`                             |
-| `rubylib`             | Search path for user libraries. <br/><br/>Default: `$OPENHAB_CONF/automation/ruby/lib`                     |
-| `dependency_tracking` | Enable dependency tracking. <br/><br/>Default: `true`                                                      |
-| `local_context`       | See notes below. <br/><br/>Default: `singlethread`                                                         |
-| `local_variables`     | See notes below. <br/><br/>Default: `transient`                                                            |
+| `gems`                | A list of gems to install. <br/><br/>Default: `openhab-scripting=~>5.0.0`                                |
+| `check_update`        | Check for updated version of `gems` on start up or settings change. <br/><br/>Default: `true`            |
+| `require`             | List of scripts to be required automatically. <br/><br/>Default: `openhab/dsl`                           |
+| `rubylib`             | Search path for user libraries. <br/><br/>Default: `$OPENHAB_CONF/automation/ruby/lib`                   |
+| `dependency_tracking` | Enable dependency tracking. <br/><br/>Default: `true`                                                    |
+| `local_context`       | See notes below. <br/><br/>Default: `singlethread`                                                       |
+| `local_variables`     | See notes below. <br/><br/>Default: `transient`                                                          |
 
 When using file-based configuration, these parameters must be prefixed with `org.openhab.automation.jrubyscripting:`, for example:
 
@@ -143,13 +144,13 @@ org.openhab.automation.jrubyscripting:gems=openhab-scripting=~>5.0
 org.openhab.automation.jrubyscripting:require=openhab/dsl
 ```
 
-### gem_home <!-- omit from toc -->
+### gem_home
 
 Path to where Ruby Gems will be installed to and loaded from. The directory will be created if necessary.
 You can use `RUBY_ENGINE_VERSION`, `RUBY_ENGINE` and/or `RUBY_VERSION` replacements in this value
 to automatically point to a new directory when the addon is updated with a new version of JRuby.
 
-### gems <!-- omit from toc -->
+### gems
 
 A comma separated list of [Ruby Gems](https://rubygems.org/) to install.
 
@@ -171,34 +172,34 @@ Examples:
 | `openhab-scripting=~>5.0, faraday=~>2.7;>=2.7.4` | install `openhab-scripting` gem version 5.x and `faraday` gem version 2.7.4 or higher, but less than 3.0 |
 | `gem1= >= 2.2.1; <= 2.2.5`                       | install `gem1` gem version 2.2.1 or above, but less than or equal to version 2.2.5                       |
 
-### check_update <!-- omit from toc -->
+### check_update
 
 Check RubyGems for updates to the above gems when openHAB starts or JRuby settings are changed.
 Otherwise it will try to fulfil the requirements with locally installed gems, and you can manage them yourself
 with an external Ruby by setting the same GEM_HOME.
 
-### require <!-- omit from toc -->
+### require
 
 A comma separated list of script names to be required by the JRuby Scripting Engine at the beginning of user scripts.
 The default is to require the helper library.
 
-### rubylib <!-- omit from toc -->
+### rubylib
 
 Search path for user libraries. Separate each path with a colon (semicolon in Windows).
 
-### dependency_tracking <!-- omit from toc -->
+### dependency_tracking
 
 Dependency tracking allows your scripts to automatically reload when one of its dependencies is updated.
 You may want to disable dependency tracking if you plan on editing or updating a shared library,
 but don't want all your scripts to reload until you can test it.
 
-### local_context <!-- omit from toc -->
+### local_context
 
 The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby.
 Valid values are: `singleton`, `threadsafe`, `singlethread`, or `concurrent`.
 See [this](https://github.com/jruby/jruby/wiki/RedBridge#context-instance-type) for options and details.
 
-### local_variables <!-- omit from toc -->
+### local_variables
 
 Defines how variables are shared between Ruby and Java. Valid values are: `transient`, `persistent`, or `global`.
 See the [JRuby documentation](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details.
@@ -212,13 +213,13 @@ The quickest way to add rules is through the openHAB Web UI.
 Advanced users, or users migrating scripts from existing systems may want to use
 [File Based Scripts](#file-based-scripts) for managing rules using files in the user configuration directory.
 
-#### Adding Triggers <!-- omit from toc -->
+#### Adding Triggers
 
 Using the openHAB UI, first create a new rule and set a trigger condition.
 
 ![openHAB Rule Configuration](docs/images/rule-config.png)
 
-#### Adding Actions <!-- omit from toc -->
+#### Adding Actions
 
 Select "Add Action" and then select "Run Script" with "Ruby".
 This will bring up an empty script editor where you can enter your JavaScript.
@@ -263,8 +264,8 @@ When you use "Item event" as trigger (i.e. "[item] received a command", "[item]
 
 This tables gives an overview of the `event` object for most common trigger types. For full details, explore [OpenHAB::Core::Events](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Events.html).
 
-| Property Name | Type                                         | Trigger Types                          | Description                                          | Rules DSL Equivalent   |
-| ------------- | -------------------------------------------- | -------------------------------------- | ---------------------------------------------------- | ---------------------- |
+| Property Name | Type                                                                                        | Trigger Types                          | Description                                          | Rules DSL Equivalent   |
+| ------------- | ------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------- | ---------------------- |
 | `state`       | [State](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/State.html) or `nil` | `[item] changed`, `[item] was updated` | State that triggered event                           | `triggeringItem.state` |
 | `was`         | [State](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/State.html) or `nil` | `[item] changed`                       | Previous state of Item or Group that triggered event | `previousState`        |
 | `command`     | [Command](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/Command.html)      | `[item] received a command`            | Command that triggered event                         | `receivedCommand`      |
@@ -433,7 +434,7 @@ Get a sorted list of Group members matching a condition:
 sorted_items_by_battery_level = gBattery.members
                                         .select(&:state?) # only include non NULL / UNDEF members
                                         .select { |item| item.state < 20 } # select only those with low battery
-                                        .sort_by(&:state) 
+                                        .sort_by(&:state)
 ```
 
 Get a list of values mapped from the members of a group:
@@ -463,7 +464,7 @@ My_Item << ON
 Note: all possible commands are supported on the corresponding item types, e.g. `on`, `off`, `up`, `down`, `play`, `pause`, `stop`, etc.
 For more details, see the individual item classes under [OpenHAB::Core::Items](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Items.html).
 
-##### Sending Commands to an Item Only When Its State is Different <!-- omit from toc -->
+##### Sending Commands to an Item Only When Its State is Different
 
 ```ruby
 My_Item.ensure.on
@@ -474,7 +475,7 @@ My_Item.ensure << ON
 logger.info("Turning off the light") if My_Item.ensure.off
 ```
 
-##### Timed Commands <!-- omit from toc -->
+##### Timed Commands
 
 A [Timed Command](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Items/TimedCommand.html) is similar to the openHAB Item's [expire parameter](https://www.openhab.org/docs/configuration/items.html#parameter-expire) but it offers more flexibility.
 It removes the need to manually create a timer.
@@ -523,7 +524,7 @@ if My_Item.state?
 end
 ```
 
-##### Comparing Item's State <!-- omit from toc -->
+##### Comparing Item's State
 
 ```ruby
 String_Item.state == 'test string'
@@ -532,14 +533,14 @@ items['Number_Item'].state == 10
 
 # Compare Quantity Types
 Temperature_Item.state > 24 | '°C'
-Indoor_Temperature.state > Outdoor_Temperature.state 
+Indoor_Temperature.state > Outdoor_Temperature.state
 Indoor_Temperature.state > Outdoor_Temperature.state + 5 | '°C'
 Indoor_Temperature.state - Outdoor_Temperature.state > 5 | '°C'
 ```
 
 See [unit block](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL.html#unit-class_method)
 
-##### Range checking <!-- omit from toc -->
+##### Range checking
 
 Types that are comparable, such as [StringType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/StringType.html), [DateTimeType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/DateTimeType.html), [DecimalType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/DecimalType.html), [PercentType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/PercentType.html),
 include Ruby's [Comparable](https://docs.ruby-lang.org/en/master/Comparable.html) module which provides
@@ -550,7 +551,7 @@ String_Item.update("Freddy")
 String_Item.state.between?("E", "G") # => true
 
 Number_Item.update(10)
-if Number_Item.state.between?(5, 20) 
+if Number_Item.state.between?(5, 20)
   logger.info "Number_Item falls within the expected range"
 end
 
@@ -569,7 +570,7 @@ end
 ((20|"°C")..(24|"°C")).cover?(Temperature_Item.state)
 ```
 
-##### Loose Type Comparisons <!-- omit from toc -->
+##### Loose Type Comparisons
 
 Some openHAB item types can accept different command types.
 For example, a [DimmerItem](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Items/DimmerItem.html) can accept a command with an [OnOffType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/OnOffType.html), [IncreaseDecreaseType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/IncreaseDecreaseType.html) or a [PercentType](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Types/PercentType.html).
@@ -798,7 +799,7 @@ end
 
 When a script is unloaded, all created timers are automatically cancelled.
 
-#### Accessing Variables <!-- omit from toc -->
+#### Accessing Variables
 
 You can access all variables of the current context in the created timers.
 
@@ -816,7 +817,7 @@ end
 my_var = "Hello mutation!" # When the timer runs, it will log "Hello mutation!" instead of "Hello world!"
 ```
 
-#### Reschedule a Timer <!-- omit from toc -->
+#### Reschedule a Timer
 
 A timer can be rescheduled inside the timer body
 
@@ -855,7 +856,7 @@ rule 'cancel timer' do
 end
 ```
 
-#### Manage Multiple Timers <!-- omit from toc -->
+#### Manage Multiple Timers
 
 Multiple timers can be managed in the traditional way by storing the timer objects in a Hash:
 
@@ -863,7 +864,7 @@ Multiple timers can be managed in the traditional way by storing the timer objec
 @timers ||= {}
 
 if @timers[event.item]
-  @timers[event.item].reschedule 
+  @timers[event.item].reschedule
 else
   @timers[event.item] = after 3.minutes do # Use the triggering item as the timer ID
     event.item.off
@@ -947,7 +948,7 @@ Several options are available for time related code, including but not limited t
 - Ruby [Time](https://docs.ruby-lang.org/en/master/Time.html) - represents a specific instant with a date and time
 - Ruby [DateTime](https://docs.ruby-lang.org/en/master/DateTime.html) - represents a specific instant with a date and time
 
-#### Durations <!-- omit from toc -->
+#### Durations
 
 Ruby [integers](https://docs.ruby-lang.org/en/master/Integer.html) and [floats](https://docs.ruby-lang.org/en/master/Float.html) are extended with several methods to support durations.
 These methods create a new [Duration](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/CoreExt/Java/Duration.html) or [Period](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/CoreExt/Java/Period.html) object that is used by the [every](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/BuilderDSL.html#every-instance_method) trigger, [delay](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/BuilderDSL.html#delay-instance_method) block, the for option of [changed](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/BuilderDSL.html#changed-instance_method) triggers, and [timers](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Timer.html).
@@ -975,7 +976,7 @@ rule "Timer example" do
 end
 ```
 
-#### Time Comparisons, Conversions, and Arithmetic <!-- omit from toc -->
+#### Time Comparisons, Conversions, and Arithmetic
 
 Comparisons, conversions and arithmetic are automatic between Java and Ruby types.
 Note that anytime you do a comparison between a type with more specific data, and a type missing specific data, the comparison is done as if the more specific data is at the beginning of its period.
@@ -1044,7 +1045,7 @@ end
 
 # Comparing Time against ZonedDateTime with `>`
 sunset = things["astro:sun:home"].get_event_time("SUN_SET", nil, nil)
-if Time.now > sunset 
+if Time.now > sunset
   logger.info "it is after sunset"
 end
 
@@ -1059,7 +1060,7 @@ elapsed_time = Time.now - Motion_Sensor.last_update
 elapsed_time = ZonedDateTime.now - Motion_Sensor.last_update
 
 # Using `-` operator with ZonedDateTime
-# Comparing two ZonedDateTime using `<` 
+# Comparing two ZonedDateTime using `<`
 Motion_Sensor.last_update < Light_Item.last_update - 10.minutes
 # is the same as:
 Motion_Sensor.last_update.before?(Light_Item.last_update.minus_minutes(10))
@@ -1078,7 +1079,7 @@ Time.at(1669684403).to_zoned_date_time
 java.time.Instant.of_epoch_second(1669684403).at_zone(ZoneId.system_default)
 ```
 
-#### Ranges <!-- omit from toc -->
+#### Ranges
 
 Ranges of date time objects work as expected.
 Make sure to use `#cover?` instead of `#include?` to do a simple comparison, instead of generating an array and searching it linearly.
@@ -1130,6 +1131,78 @@ Date.today.weekend? # => true
 Date.today.in_dayset?(:school) # => false
 ```
 
+### Rules, Scripts, and Scenes
+
+[Rules](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Rules/Rule.html), Scenes and Scripts can be accessed using the
+[rules](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Rules/Registry.html) object. For example, to execute/trigger a rule:
+
+```ruby
+rules[rule_uid].trigger
+```
+
+Scenes are rules with a `Scene` tag, and Scripts are rules with a `Script` tag. They can be found
+using their uid just like normal rules, i.e. `rules[uid]`. For convenience, a list of all Scenes are
+available through the enumerable [rules.scenes](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Rules/Registry.html#scenes-instance_method),
+and a list of all Scripts through [rules.scripts](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/Core/Rules/Registry.html#scripts-instance_method).
+
+Example: All scenes tagged `sunrise` will be triggered at sunrise, and all scenes tagged
+`sunset` will be triggered at sunset. Note: these use the [Terse Rule](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/Terse.html) syntax.
+
+```ruby
+channel("astro:sun:home:rise#event") { rules.scenes.tagged("sunrise").each(&:trigger) }
+channel("astro:sun:home:set#event") { rules.scenes.tagged("sunset").each(&:trigger) }
+```
+
+Or it can be written as one rule with the help of [trigger attachments](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/BuilderDSL.html#Triggers-group).
+
+```ruby
+rule "Activate scenes at sunset/sunrise" do
+  channel "astro:sun:home:rise#event", attach: "sunrise"
+  channel "astro:sun:home:set#event", attach: "sunset"
+  run { |event| rules.scenes.tagged(event.attachment).each(&:trigger) }
+end
+```
+
+Get the UID of a Rule
+
+```ruby
+rule_obj = rule 'my rule name' do
+  received_command My_Item
+  run do
+    # rule code here
+  end
+end
+
+rule_uid = rule_obj.uid
+```
+
+A rule's UID can also be specified at rule creation
+
+```ruby
+rule "my rule name", id: "my_unique_rule_uid" do
+  # ...
+end
+
+# or
+rule "my rule name" do
+  uid "my_unique_rule_uid"
+  # ...
+end
+```
+
+Get the UID of a Rule by Name
+
+```ruby
+rule_uid = rules.find { |rule| rule.name == 'This is the name of my rule' }.uid
+```
+
+Enable or Disable a Rule by UID
+
+```ruby
+rules[rule_uid].enable
+rules[rule_uid].disable
+```
+
 ### Gems
 
 [Bundler](https://bundler.io/) is integrated, enabling any [Ruby gem](https://rubygems.org/) compatible with JRuby to be used within rules. This permits easy access to the vast ecosystem of libraries within the Ruby community.
@@ -1168,6 +1241,81 @@ def my_lib_version
 end
 ```
 
+### Transformations
+
+This add-on also provides the necessary infrastructure to use Ruby for writing [transformations](https://www.openhab.org/docs/configuration/transformations.html).
+
+The main value to be transformed is given to the script in a variable called `input`.
+Note that the values are passed to the transformation as Strings even for numeric items and data types.
+
+**Note**: In openHAB 3.4, due to an [issue](https://github.com/jruby/jruby/issues/5876) in the current version of JRuby,
+you will need to begin your script with `input ||= nil` (and `a ||= nil` etc. for additional query variables) so that
+JRuby will recognize the variables as variables--rather than method calls--when it's parsing the script.
+Otherwise you will get errors like `(NameError) undefined local variable or method 'input' for main:Object`.
+This is not necessary in openHAB 4.0+.
+
+#### File Based Transformations
+
+Once the addon is installed, you can create a Ruby file in the `$OPENHAB_CONF/transform` directory, with the extension `.script`.
+It's important that the extension is `.script` so that the core `SCRIPT` transform service will recognize it.
+When referencing the file, you need to specify the `SCRIPT` transform, with `rb` as the script type: `SCRIPT(rb:mytransform.script):%s`.
+
+You can also specify additional variables to be set in the script using a URI-like query syntax: `SCRIPT(rb:mytransform.script?a=1&b=c):%s`
+in order to share a single script with slightly different parameters for different items.
+
+##### Example: Display the wind direction in degrees and cardinal direction
+
+`weather.items`
+
+```Xtend
+Number:Angle Exterior_WindDirection "Wind Direction [SCRIPT(rb:compass.script):%s]" <wind>
+```
+
+`compass.script`
+
+```ruby
+DIRECTIONS = %w[N NE E SE S SW W NW N].freeze
+
+if input.nil? || input == "NULL" || input == "UNDEF"
+  "-"
+else
+  cardinal = DIRECTIONS[(input.to_f / 45).round]
+  "#{cardinal} (#{input.to_f.round}°)"
+end
+```
+
+Given a state of `82 °`, this will produce a formatted state of `E (82°)`.
+
+##### Example: Display the number of lights that are on/off within a group
+
+```Xtend
+Group gIndoorLights "Indoor Lights [SCRIPT(rb:group_count.script?group=gIndoorLights):%s]"
+Group gOutdoorLights "Outdoor Lights [SCRIPT(rb:group_count.script?group=gOutdoorLights):%s]"
+```
+
+`group_count.script`
+
+```ruby
+items[group].all_members.then { |all| "#{all.select(&:on?).size}/#{all.size}" }
+```
+
+When 3 lights out of 10 lights are on, this will produce a formatted state of `3/10`
+
+#### Inline Transformations
+
+Inline transformations are supported too. For example, to display the temperature in both °C and °F:
+
+```Xtend
+Number:Temperature Outside_Temperature "Outside Temperature [SCRIPT(rb:|  input.to_f.|('°C').then { |t| %(#{t.format('%d °C')} / #{t.to_unit('°F').format('%d °F')}) }   ):%s]"
+```
+
+When the item contains `0 °C`, this will produce a formatted state of `0 °C / 32 °F`.
+
+### Profile
+
+You can create an openHAB profile in JRuby that can be applied to item channel links.
+For more details, see [#profile](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL.html#profile-class_method).
+
 ## File Based Rules
 
 ### Basic Rule Structure
@@ -1204,7 +1352,7 @@ end
 
 See [#changed](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/BuilderDSL.html#changed-instance_method)
 
-##### Detecting Change Duration <!-- omit from toc -->
+##### Detecting Change Duration
 
 Only execute a rule when an item state changed and stayed the same for a period of time. This method
 can only be done using a file-based rule.
@@ -1300,7 +1448,7 @@ end
 
 See [#cron](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/BuilderDSL.html#cron-instance_method)
 
-##### `every` Trigger <!-- omit from toc -->
+##### `every` Trigger
 
 ```ruby
 rule "run every day" do
@@ -1444,48 +1592,6 @@ received_command(My_Switch, to: ON) { My_Light.on }
 
 See [Terse Rules](https://openhab.github.io/openhab-jruby/5.0/OpenHAB/DSL/Rules/Terse.html) for full details.
 
-### Rule Manipulations
-
-Get the UID of a Rule
-
-```ruby
-rule_obj = rule 'my rule name' do
-  received_command My_Item
-  run do
-    # rule code here
-  end
-end
-
-rule_uid = rule_obj.uid
-```
-
-A rule's UID can also be specified at rule creation
-
-```ruby
-rule "my rule name", id: "my_unique_rule_uid" do
-  # ...
-end
-```
-
-Get the UID of a Rule by Name
-
-```ruby
-rule_uid = rules.find { |rule| rule.name == 'This is the name of my rule' }.uid
-```
-
-Enable or Disable a Rule by UID
-
-```ruby
-rules[rule_uid].enable
-rules[rule_uid].disable
-```
-
-Run a Rule by UID
-
-```ruby
-rules[rule_uid].trigger
-```
-
 ### Early Exit From a Rule
 
 You can use `next` within a file-based rule, because it's in a block:
@@ -1572,39 +1678,6 @@ script_unloaded do
 end
 ```
 
-### Transformations
-
-This add-on also provides the necessary infrastructure to use Ruby for writing [transformations](https://www.openhab.org/docs/configuration/transformations.html).
-Once the addon is installed, you can create a Ruby file in the `$OPENHAB_CONF/transform` directory, with the extension `.script`.
-It's important that the extension is `.script` so that the core `SCRIPT` transform service will recognize it.
-When referencing the file, you need to specify the `SCRIPT` transform, with `rb` as the script type: `SCRIPT(rb:mytransform.script):%s`.
-You can also specify additional variables to be set in the script using a URI-like query syntax: `SCRIPT(rb:mytransform.script?a=1b=c):%s` in order to share a single script with slightly different parameters for different items.
-
-**Note**: Due to an [issue](https://github.com/jruby/jruby/issues/5876) in the current version of JRuby, you will need to begin your script with `input ||= nil` (and `a ||= nil` etc. for additional query variables) so that JRuby will recognize the variables as variables--rather than method calls--when it's parsing the script.
-Otherwise you will get errors like `(NameError) undefined local variable or method 'input' for main:Object`.
-
-`compass.script`
-
-```ruby
-input ||= nil
-DIRECTIONS = %w[N NE E SE S SW W NW N].freeze
-
-if input.nil? || input == "NULL" || input == "UNDEF"
-  "-"
-else
-  cardinal = DIRECTIONS[(input.to_f / 45).round]
-  "#{cardinal} (#{input.to_i}°)"
-end
-```
-
-`weather.items`
-
-```Xtend
-Number:Angle Exterior_WindDirection "Wind Direction [SCRIPT(rb:compass.script):%s]" <wind>
-```
-
-Given a state of `82 °`, this will produce a formatted state of `E (82°)`.
-
 ## Calling Java From JRuby
 
 JRuby can access almost any Java object that's available in the current JVM.