openhab-scripting 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/workflow.yml +327 -0
  3. data/.gitignore +17 -0
  4. data/.java-version +1 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +113 -0
  8. data/Gemfile +28 -0
  9. data/Gemfile.lock +245 -0
  10. data/Guardfile +35 -0
  11. data/LICENSE +277 -0
  12. data/README.md +23 -0
  13. data/Rakefile +406 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/config/userdata/config/org/openhab/restauth.config +3 -0
  17. data/cucumber.yml +1 -0
  18. data/docs/_config.yml +135 -0
  19. data/docs/contributing/index.md +47 -0
  20. data/docs/examples/conversions.md +123 -0
  21. data/docs/examples/index.md +61 -0
  22. data/docs/index.md +19 -0
  23. data/docs/installation/index.md +26 -0
  24. data/docs/motivation/index.md +27 -0
  25. data/docs/usage/execution.md +9 -0
  26. data/docs/usage/execution/delay.md +48 -0
  27. data/docs/usage/execution/otherwise.md +30 -0
  28. data/docs/usage/execution/run.md +70 -0
  29. data/docs/usage/execution/triggered.md +48 -0
  30. data/docs/usage/guards.md +51 -0
  31. data/docs/usage/guards/between.md +30 -0
  32. data/docs/usage/guards/not_if.md +41 -0
  33. data/docs/usage/guards/only_if.md +40 -0
  34. data/docs/usage/index.md +11 -0
  35. data/docs/usage/items.md +66 -0
  36. data/docs/usage/items/contact.md +84 -0
  37. data/docs/usage/items/dimmer.md +147 -0
  38. data/docs/usage/items/groups.md +76 -0
  39. data/docs/usage/items/number.md +225 -0
  40. data/docs/usage/items/string.md +49 -0
  41. data/docs/usage/items/switch.md +85 -0
  42. data/docs/usage/misc.md +7 -0
  43. data/docs/usage/misc/actions.md +108 -0
  44. data/docs/usage/misc/duration.md +21 -0
  45. data/docs/usage/misc/gems.md +25 -0
  46. data/docs/usage/misc/logging.md +21 -0
  47. data/docs/usage/misc/metadata.md +128 -0
  48. data/docs/usage/misc/store_states.md +42 -0
  49. data/docs/usage/misc/time_of_day.md +69 -0
  50. data/docs/usage/misc/timers.md +67 -0
  51. data/docs/usage/rule.md +43 -0
  52. data/docs/usage/things.md +29 -0
  53. data/docs/usage/triggers.md +8 -0
  54. data/docs/usage/triggers/changed.md +57 -0
  55. data/docs/usage/triggers/channel.md +54 -0
  56. data/docs/usage/triggers/command.md +69 -0
  57. data/docs/usage/triggers/cron.md +19 -0
  58. data/docs/usage/triggers/every.md +76 -0
  59. data/docs/usage/triggers/updated.md +78 -0
  60. data/lib/openhab.rb +39 -0
  61. data/lib/openhab/configuration.rb +16 -0
  62. data/lib/openhab/core/cron.rb +27 -0
  63. data/lib/openhab/core/debug.rb +34 -0
  64. data/lib/openhab/core/dsl.rb +47 -0
  65. data/lib/openhab/core/dsl/actions.rb +107 -0
  66. data/lib/openhab/core/dsl/entities.rb +103 -0
  67. data/lib/openhab/core/dsl/gems.rb +29 -0
  68. data/lib/openhab/core/dsl/group.rb +91 -0
  69. data/lib/openhab/core/dsl/items/items.rb +39 -0
  70. data/lib/openhab/core/dsl/items/number_item.rb +217 -0
  71. data/lib/openhab/core/dsl/items/string_item.rb +102 -0
  72. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +4 -0
  73. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +22 -0
  74. data/lib/openhab/core/dsl/monkey_patch/events.rb +5 -0
  75. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +13 -0
  76. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +25 -0
  77. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +26 -0
  78. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +54 -0
  79. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +125 -0
  80. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +27 -0
  81. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +130 -0
  82. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +259 -0
  83. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +86 -0
  84. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +69 -0
  85. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +46 -0
  86. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +5 -0
  87. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +24 -0
  88. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +41 -0
  89. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +25 -0
  90. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +23 -0
  91. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +7 -0
  92. data/lib/openhab/core/dsl/property.rb +85 -0
  93. data/lib/openhab/core/dsl/rule/channel.rb +41 -0
  94. data/lib/openhab/core/dsl/rule/cron.rb +115 -0
  95. data/lib/openhab/core/dsl/rule/guard.rb +99 -0
  96. data/lib/openhab/core/dsl/rule/item.rb +207 -0
  97. data/lib/openhab/core/dsl/rule/rule.rb +374 -0
  98. data/lib/openhab/core/dsl/rule/triggers.rb +77 -0
  99. data/lib/openhab/core/dsl/states.rb +63 -0
  100. data/lib/openhab/core/dsl/things.rb +93 -0
  101. data/lib/openhab/core/dsl/time_of_day.rb +203 -0
  102. data/lib/openhab/core/dsl/timers.rb +85 -0
  103. data/lib/openhab/core/dsl/types/quantity.rb +255 -0
  104. data/lib/openhab/core/dsl/units.rb +41 -0
  105. data/lib/openhab/core/duration.rb +69 -0
  106. data/lib/openhab/core/log.rb +175 -0
  107. data/lib/openhab/core/patch_load_path.rb +7 -0
  108. data/lib/openhab/core/startup_delay.rb +22 -0
  109. data/lib/openhab/osgi.rb +52 -0
  110. data/lib/openhab/version.rb +9 -0
  111. data/openhab-scripting.gemspec +30 -0
  112. data/openhab_rules/warmup.rb +5 -0
  113. metadata +157 -0
@@ -0,0 +1,255 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'forwardable'
5
+
6
+ module OpenHAB
7
+ module Core
8
+ module DSL
9
+ #
10
+ # Ruby implementation of OpenHAB Types
11
+ #
12
+ module Types
13
+ #
14
+ # Ruby implementation for OpenHAB quantities
15
+ #
16
+ class Quantity < Numeric
17
+ extend Forwardable
18
+ include Logging
19
+
20
+ def_delegator :@quantity, :to_s
21
+
22
+ java_import org.openhab.core.library.types.QuantityType
23
+ java_import 'tec.uom.se.format.SimpleUnitFormat'
24
+ java_import 'tec.uom.se.AbstractUnit'
25
+
26
+ OPERATIONS = {
27
+ '+' => 'add',
28
+ '-' => 'subtract',
29
+ '*' => 'multiply',
30
+ '/' => 'divide'
31
+ }.freeze
32
+
33
+ private_constant :OPERATIONS
34
+
35
+ attr_reader :quantity
36
+
37
+ #
38
+ # Create a new Quantity
39
+ #
40
+ # @param [Java::org::openhab::core::library::types::QuantityType] quantity OpenHAB quantity to delegate to
41
+ #
42
+ def initialize(quantity)
43
+ @quantity = case quantity
44
+ when String
45
+ QuantityType.new(quantity)
46
+ when QuantityType
47
+ quantity
48
+ when Numeric
49
+ QuantityType.new(BigDecimal(quantity).to_java, AbstractUnit::ONE)
50
+ else
51
+ raise "Unexpected type #{quantity.class} provided to Quantity initializer"
52
+ end
53
+ super()
54
+ end
55
+
56
+ #
57
+ # Convert this quantity into a another unit
58
+ #
59
+ # @param [Object] other String or Unit to convert to
60
+ #
61
+ # @return [Quantity] This quantity converted to another unit
62
+ #
63
+ def |(other)
64
+ other = SimpleUnitFormat.instance.unitFor(other) if other.is_a? String
65
+
66
+ Quantity.new(quantity.to_unit(other))
67
+ end
68
+
69
+ #
70
+ # Compare this quantity
71
+ #
72
+ # @param [Object] other object to compare to
73
+ #
74
+ # @return [Integer] -1,0,1 if this object is less than, equal to, or greater than the supplied object,
75
+ # nil if it cannot be compared
76
+ #
77
+ def <=>(other)
78
+ logger.trace("Comparing #{self} to #{other}")
79
+ case other
80
+ when Quantity
81
+ logger.trace("Comparing Quantity #{self} to Quantity #{other}")
82
+ convert_unit(quantity).compare_to(convert_unit(other.quantity))
83
+ when QuantityType
84
+ other = convert_unit(other)
85
+ quantity.compare_to(other)
86
+ when String
87
+ other = QuantityType.new(other)
88
+ other = convert_unit(other)
89
+ quantity.compare_to(other)
90
+ when Numeric
91
+ quantity.compare_to(QuantityType.new(other, unit)) if unit
92
+ end
93
+ end
94
+
95
+ #
96
+ # Coerce other object into a Quantity
97
+ #
98
+ # @param [Object] other object to convert to Quantity
99
+ #
100
+ # @return [Array] of self and other object as Quantity types, nil if object cannot be coerced
101
+ #
102
+ def coerce(other)
103
+ logger.trace("Coercing #{self} as a request from #{other.class}")
104
+ case other
105
+ when Quantity
106
+ [other.quantity, quantity]
107
+ when QuantityType
108
+ [other, quantity]
109
+ when Numeric
110
+ [Quantity.new(other), self]
111
+ end
112
+ end
113
+
114
+ #
115
+ # Forward missing methods to Openhab Quantity Item if they are defined
116
+ #
117
+ # @param [String] meth name of method invoked
118
+ # @param [Array] args arguments to invoked method
119
+ # @param [Proc] block block passed ot method
120
+ #
121
+ # @return [Object] result of delegation
122
+ #
123
+ def method_missing(meth, *args, &block)
124
+ if quantity.respond_to?(meth)
125
+ quantity.__send__(meth, *args, &block)
126
+ elsif ::Kernel.method_defined?(meth) || ::Kernel.private_method_defined?(meth)
127
+ ::Kernel.instance_method(meth).bind_call(self, *args, &block)
128
+ else
129
+ super(meth, *args, &block)
130
+ end
131
+ end
132
+
133
+ #
134
+ # Negate the quantity
135
+ #
136
+ # @return [Quantity] This quantity negated
137
+ #
138
+ def -@
139
+ Quantity.new(quantity.negate)
140
+ end
141
+
142
+ OPERATIONS.each do |operation, method|
143
+ define_method(operation) do |other|
144
+ logger.trace("Executing math operation '#{operation}' on quantity #{inspect} with other type #{other.class} and value #{other.inspect}")
145
+ a, b = case other
146
+ when Quantity
147
+ [quantity, other.quantity]
148
+ when String
149
+ [quantity, QuantityType.new(other)]
150
+ when NumberItem
151
+ a, b = other.coerce(self)
152
+ logger.trace("Number Item coerced result a(#{a.class})='#{a}' b(#{b.class})='#{b}'")
153
+ [a.quantity, b.quantity]
154
+ when Numeric
155
+ [quantity, QuantityType.new(BigDecimal(other).to_java, AbstractUnit::ONE)]
156
+ else
157
+ raise TypeError,
158
+ "Operation '#{operation}' cannot be performed between #{self} and #{other.class}"
159
+ end
160
+ logger.trace("Coerced a='#{a}' with b='#{b}'")
161
+ a, b = unitize(a, b, operation)
162
+ logger.trace("Unitized a='#{a}' b='#{b}'")
163
+ logger.trace("Performing operation '#{operation}' with method '#{method}' on a='#{a}' with b='#{b}'")
164
+ Quantity.new(a.public_send(method, b))
165
+ end
166
+ end
167
+
168
+ #
169
+ # Provide details about quantity object
170
+ #
171
+ # @return [String] Representing details about the quantity object
172
+ #
173
+ def inspect
174
+ if @quantity.unit == AbstractUnit::ONE
175
+ "unit=#{@quantity.unit}, value=#{@quantity.to_string}"
176
+ else
177
+ @quantity.to_string
178
+ end
179
+ end
180
+
181
+ private
182
+
183
+ DIMENSIONLESS_NON_UNITIZED_OPERATIONS = %w[* /].freeze
184
+
185
+ # Dimensionless numbers should only be unitzed for addition and subtraction
186
+
187
+ #
188
+ # Checks if an item should be unitized
189
+ #
190
+ # @param [Quantity] quantity to check
191
+ # @param [String] operation quantity is being used with
192
+ #
193
+ # @return [Boolean] True if the quantity should be unitzed based on the unit and operation, false otherwise
194
+ #
195
+ def unitize?(quantity, operation)
196
+ if quantity.unit == AbstractUnit::ONE && DIMENSIONLESS_NON_UNITIZED_OPERATIONS.include?(operation)
197
+ false
198
+ else
199
+ true
200
+ end
201
+ end
202
+
203
+ #
204
+ # Convert the unit for the quantity
205
+ #
206
+ # @param [Quantity] quantity being converted
207
+ #
208
+ # @return [Quantity] Quantity coverted to unit set by unit block
209
+ #
210
+ def convert_unit(quantity)
211
+ if unit
212
+ case quantity.unit
213
+ when AbstractUnit::ONE
214
+ logger.trace("Converting dimensionless #{quantity} to #{unit}")
215
+ QuantityType.new(quantity.to_big_decimal, unit)
216
+ when unit
217
+ quantity
218
+ else
219
+ logger.trace("Converting dimensioned item #{inspect} to #{unit}")
220
+ converted = quantity.to_unit(unit)
221
+ raise "Conversion from #{quantity.unit} to #{unit} failed" if converted.nil?
222
+
223
+ converted
224
+ end
225
+ else
226
+ quantity
227
+ end
228
+ end
229
+
230
+ #
231
+ # Convert quantities to appropriate units
232
+ #
233
+ # @param [Quantity] quantity_a Quantity on left side of operation
234
+ # @param [Quantity] quantity_b Quantity on right side of operation
235
+ # @param [String] operation Math operation
236
+ #
237
+ # @return [Array] of quantites in correct units for the supplied operation and set unit
238
+ #
239
+ def unitize(quantity_a, quantity_b, operation)
240
+ [quantity_a, quantity_b].map { |qt| unitize?(qt, operation) ? convert_unit(qt) : qt }
241
+ end
242
+
243
+ #
244
+ # Get the unit from the current thread local variable
245
+ #
246
+ # @return [Object] Unit or string representation of Unit, or nil if not set
247
+ #
248
+ def unit
249
+ Thread.current.thread_variable_get(:unit)
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+
5
+ # Import Imperial and SI Units overriding provided values
6
+ %i[ImperialUnits SIUnits].each do |type|
7
+ Object.send(:remove_const, type)
8
+ java_import "org.openhab.core.library.unit.#{type}"
9
+ end
10
+
11
+ Object.send(:remove_const, :QuantityType)
12
+ java_import org.openhab.core.library.types.QuantityType
13
+
14
+ module OpenHAB
15
+ module Core
16
+ module DSL
17
+ #
18
+ # Provides support for interacting with OpenHAB Units of Measurement
19
+ #
20
+ module Units
21
+ java_import 'tec.uom.se.format.SimpleUnitFormat'
22
+
23
+ #
24
+ # Sets a thread local variable to the supplied unit such that classes operating inside the block
25
+ # can perform automatic conversions to the supplied unit for NumberItems
26
+ #
27
+ # @param [Object] unit OpenHAB Unit or String representing unit
28
+ # @yield [] Block executed in context of the supplied unit
29
+ #
30
+ #
31
+ def unit(unit)
32
+ unit = SimpleUnitFormat.instance.unitFor(unit) if unit.is_a? String
33
+ Thread.current.thread_variable_set(:unit, unit)
34
+ yield
35
+ ensure
36
+ Thread.current.thread_variable_set(:unit, nil)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/core/cron'
4
+
5
+ module OpenHAB
6
+ module Core
7
+ #
8
+ # This class represents a duration of time
9
+ #
10
+ class Duration
11
+ include OpenHAB::Core::Cron
12
+
13
+ # @return [Array] of supported temperal units (milliseconds, seconds, minutes and hours)
14
+ TEMPORAL_UNITS = %i[MILLISECONDS SECONDS MINUTES HOURS].freeze
15
+
16
+ #
17
+ # Create a new Duration object
18
+ #
19
+ # @param [Symbol] temporal_unit Unit for duration
20
+ # @param [Integer] amount of that unit
21
+ #
22
+ def initialize(temporal_unit:, amount:)
23
+ unless TEMPORAL_UNITS.include? temporal_unit
24
+ raise ArgumentError,
25
+ "Unexpected Temporal Unit: #{temporal_unit}"
26
+ end
27
+
28
+ @temporal_unit = temporal_unit
29
+ @amount = amount
30
+ end
31
+
32
+ #
33
+ # Return a map
34
+ #
35
+ # @return [Map] Map with fields representing this duration @see OpenHAB::Core::Cron
36
+ #
37
+ def cron_map
38
+ case @temporal_unit
39
+ when :SECONDS
40
+ cron_expression_map.merge(second: "*/#{@amount}")
41
+ when :MINUTES
42
+ cron_expression_map.merge(minute: "*/#{@amount}")
43
+ when :HOURS
44
+ cron_expression_map.merge(hour: "*/#{@amount}")
45
+ else
46
+ raise ArgumentError, "Cron Expression not supported for temporal unit: #{temporal_unit}"
47
+ end
48
+ end
49
+
50
+ #
51
+ # Convert the duration to milliseconds
52
+ #
53
+ # @return [Integer] Duration in milliseconds
54
+ #
55
+ def to_ms
56
+ case @temporal_unit
57
+ when :MILLISECONDS
58
+ @amount
59
+ when :SECONDS
60
+ @amount * 1000
61
+ when :MINUTES
62
+ @amount * 1000 * 60
63
+ when :HOURS
64
+ @amount * 1000 * 60 * 60
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openhab/configuration'
4
+ require 'java'
5
+ require 'pp'
6
+
7
+ #
8
+ # Provides access to the OpenHAB logging using a Ruby logging methods
9
+ #
10
+ module Logging
11
+ #
12
+ # Ruby Logger that forwards messages at appropriate levels to OpenHAB Logger
13
+ #
14
+ class Logger
15
+ java_import org.slf4j.LoggerFactory
16
+
17
+ # @return [Array] Supported logging levels
18
+ LEVELS = %i[TRACE DEBUG WARN INFO ERROR].freeze
19
+
20
+ #
21
+ # Create a new logger
22
+ #
23
+ # @param [String] name of the logger
24
+ #
25
+ def initialize(name)
26
+ @sl4fj_logger = LoggerFactory.getLogger(name)
27
+ end
28
+
29
+ # Dynamically define the methods for each level as identified by the levels constant
30
+ # This creates a method for each level that looks like this
31
+ # def <level>(msg=nil, &block)
32
+ # log(severity: <level>, msg: msg, &block)
33
+ # end
34
+ LEVELS.each do |level|
35
+ method = level.to_s.downcase
36
+ define_method(method.to_s) do |msg = nil, &block|
37
+ log(severity: level, msg: msg, &block)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ #
44
+ # Log a message to the OpenHAB Logger
45
+ #
46
+ # @param [Symbol] severity Severity to log message at
47
+ # @param [Object] msg to log, if no msg supplied and a block is provided, the msg is taken from the result of the block
48
+ #
49
+ def log(severity:, msg: nil)
50
+ severity = severity.to_sym
51
+
52
+ raise ArgumentError, "Unknown Severity #{severity}" unless LEVELS.include? severity
53
+
54
+ # Dynamically check enablement of underlying logger, this expands to "is_<level>_enabled"
55
+ return unless @sl4fj_logger.send("is_#{severity.to_s.downcase}_enabled")
56
+
57
+ # Process block if no message provided
58
+ if msg.nil?
59
+ if block_given?
60
+ msg = yield
61
+ else
62
+ return
63
+ end
64
+ end
65
+
66
+ msg = message_to_string(msg: msg)
67
+
68
+ # Dynamically invoke underlying logger, this expands to "<level>(message)"
69
+ @sl4fj_logger.send(severity.to_s.downcase, msg)
70
+ end
71
+
72
+ #
73
+ # Conver the supplied message object to a String
74
+ #
75
+ # @param [object] msg object to convert
76
+ #
77
+ # @return [String] Msg object as a string
78
+ #
79
+ def message_to_string(msg:)
80
+ case msg
81
+ when ::String
82
+ msg
83
+ when ::Exception
84
+ "#{msg.message} (#{msg.class})\n#{msg.backtrace&.join("\n")}"
85
+ else
86
+ msg.inspect
87
+ end
88
+ end
89
+ end
90
+
91
+ @loggers = {}
92
+
93
+ # Return a logger with the configured log prefix plus the calling scripts name
94
+
95
+ #
96
+ # Create a logger for the current class
97
+ #
98
+ # @return [Logger] for the current class
99
+ #
100
+ def logger
101
+ Logging.logger(self.class.name)
102
+ end
103
+
104
+ class << self
105
+ #
106
+ # Injects a logger into the base class
107
+ #
108
+ # @param [String] name of the logger
109
+ #
110
+ # @return [Logger] for the supplied name
111
+ #
112
+ def logger(name)
113
+ name ||= self.class.name
114
+ @loggers[name] ||= Logging.logger_for(name)
115
+ end
116
+
117
+ #
118
+ # Configure a logger for the supplied class name
119
+ #
120
+ # @param [String] classname to configure logger for
121
+ #
122
+ # @return [Logger] for the supplied classname
123
+ #
124
+ def logger_for(classname)
125
+ configure_logger_for(classname)
126
+ end
127
+
128
+ private
129
+
130
+ #
131
+ # Configure a logger for the supplied classname
132
+ #
133
+ # @param [String] classname to create logger for
134
+ #
135
+ # @return [Logger] Logger for the supplied classname
136
+ #
137
+ def configure_logger_for(classname)
138
+ log_prefix = Configuration.log_prefix
139
+ log_prefix += if classname
140
+ ".#{classname}"
141
+ else
142
+ ".#{log_caller}"
143
+ end
144
+ Logger.new(log_prefix)
145
+ end
146
+
147
+ #
148
+ # Figure out the log prefix
149
+ #
150
+ # @return [String] Prefix for log messages
151
+ #
152
+ def log_caller
153
+ caller_locations.map(&:path)
154
+ .grep_v(%r{openhab/core/})
155
+ .grep_v(/rubygems/)
156
+ .grep_v(%r{lib/ruby})
157
+ .first
158
+ .yield_self { |caller| File.basename(caller, '.*') }
159
+ end
160
+ end
161
+
162
+ #
163
+ # Add logger method to the object that includes this module
164
+ #
165
+ # @param [Object] base Object to add method to
166
+ #
167
+ #
168
+ def self.included(base)
169
+ class << base
170
+ def logger
171
+ Logging.logger(self.class.name)
172
+ end
173
+ end
174
+ end
175
+ end