ruby-dbus 0.14.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/NEWS.md +44 -0
  3. data/README.md +3 -5
  4. data/Rakefile +26 -8
  5. data/VERSION +1 -1
  6. data/doc/Reference.md +84 -1
  7. data/examples/doc/_extract_examples +5 -0
  8. data/examples/gdbus/gdbus +21 -20
  9. data/examples/service/call_service.rb +1 -1
  10. data/lib/dbus/auth.rb +8 -8
  11. data/lib/dbus/bus.rb +23 -11
  12. data/lib/dbus/bus_name.rb +27 -0
  13. data/lib/dbus/core_ext/class/attribute.rb +23 -41
  14. data/lib/dbus/core_ext/module/redefine_method.rb +51 -0
  15. data/lib/dbus/introspect.rb +71 -26
  16. data/lib/dbus/marshall.rb +2 -1
  17. data/lib/dbus/message_queue.rb +17 -14
  18. data/lib/dbus/object.rb +380 -0
  19. data/lib/dbus/object_path.rb +24 -0
  20. data/lib/dbus/proxy_object.rb +11 -2
  21. data/lib/dbus/proxy_object_interface.rb +1 -0
  22. data/lib/dbus/type.rb +18 -0
  23. data/lib/dbus/xml.rb +4 -8
  24. data/lib/dbus.rb +3 -2
  25. data/ruby-dbus.gemspec +11 -9
  26. data/spec/binding_spec.rb +6 -2
  27. data/spec/bus_name_spec.rb +25 -0
  28. data/spec/client_robustness_spec.rb +25 -0
  29. data/spec/introspect_xml_parser_spec.rb +13 -13
  30. data/spec/main_loop_spec.rb +1 -1
  31. data/spec/object_path_spec.rb +23 -0
  32. data/spec/property_spec.rb +53 -3
  33. data/spec/proxy_object_spec.rb +9 -0
  34. data/spec/service_newapi.rb +20 -66
  35. data/spec/session_bus_spec.rb +6 -6
  36. data/spec/signal_spec.rb +33 -18
  37. data/spec/spec_helper.rb +23 -11
  38. data/spec/tools/dbus-limited-session.conf +4 -0
  39. data/spec/type_spec.rb +2 -2
  40. metadata +32 -15
  41. data/lib/dbus/core_ext/array/extract_options.rb +0 -31
  42. data/lib/dbus/core_ext/kernel/singleton_class.rb +0 -8
  43. data/lib/dbus/core_ext/module/remove_method.rb +0 -14
  44. data/lib/dbus/export.rb +0 -130
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 95dfa24c76e4ed5aeb5997bd160a4efd69a8c146
4
- data.tar.gz: 244e215c35cff67f53c7f7ac51a699c2fec22b2d
2
+ SHA256:
3
+ metadata.gz: ee629ce8a78d7cd23f718103cfd622d2a5fd67c51dab6b2a88e453c512c608f3
4
+ data.tar.gz: a8995a9526e3b957d32c503de7ad5ef781e5c464925fec8e2107eda4529aa447
5
5
  SHA512:
6
- metadata.gz: f020e993e5a6777c7ea540cf1197200aa6f1c3c7003f331b42b73cea3d5937925243bf46d2668488e8854bb7ac34d88a20934a18e90a2bb46d9fca7bcb8de764
7
- data.tar.gz: 160ebb98a13e02b982c7b634a02aa271b5899d54be289c9f5d71c0a2f8b9fcfc1190e4e19854a1a236a237f875cd108bad280a6bdbe571e68cb38afaad10b6b4
6
+ metadata.gz: 531e01c12aed4aeedaa5ce55fec2fee0c3da714211adc768c8990d2ce79509e6b925bc06d4308e9628cff109b9880dbea72878e7aeaf23c8e5fb19ddf8a249e2
7
+ data.tar.gz: 6449aa2798ed78d29c430423a92d7c8a921fd4ea244eea11fb8a84ca2eb880a4e6860325dc6a05254dc432b971d4929fc4d3a5057e423939c0574a687e7680f7
data/NEWS.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## Ruby D-Bus 0.17.0 - 2022-02-11
6
+
7
+ API:
8
+ * Export properties with `dbus_attr_accessor`, `dbus_reader` etc. ([#86][]).
9
+
10
+ Bug fixes:
11
+ * Depend on rexml which is separate since Ruby 3.0 ([#87][],
12
+ by Toshiaki Asai).
13
+ Nokogiri is faster but bigger so it remains optional.
14
+ * Fix connection in case ~/.dbus-keyrings has multiple cookies, showing
15
+ as "Oops: undefined method `zero?' for nil:NilClass".
16
+ * Add the missing name to the root introspection node.
17
+
18
+ [#86]: https://github.com/mvidner/ruby-dbus/pull/86
19
+ [#87]: https://github.com/mvidner/ruby-dbus/pull/87
20
+
21
+ ## Ruby D-Bus 0.16.0 - 2019-10-15
22
+
23
+ API:
24
+ * An invalid service name or an invalid object path will raise
25
+ instead of being sent to the bus. The bus would then drop the connection,
26
+ producing EOFError here ([#80][]).
27
+
28
+ [#80]: https://github.com/mvidner/ruby-dbus/issues/80
29
+
30
+ ## Ruby D-Bus 0.15.0 - 2018-04-30
31
+
32
+ API:
33
+ * Accessing an unknown interface will raise instead of returning nil ([#74][]).
34
+
35
+ Bug fixes:
36
+ * Fixed a conflict with activesupport 5.2 ([#71])
37
+
38
+ [#71]: https://github.com/mvidner/ruby-dbus/issues/71
39
+ [#74]: https://github.com/mvidner/ruby-dbus/pull/74
40
+
41
+ ## Ruby D-Bus 0.14.1 - 2018-01-05
42
+
43
+ Bug fixes:
44
+ * Allow registering signal handlers while a signal is being handled
45
+ ([#70][], Jan Biniok).
46
+
47
+ [#70]: https://github.com/mvidner/ruby-dbus/pull/70
48
+
5
49
  ## Ruby D-Bus 0.14.0 - 2017-10-13
6
50
 
7
51
  Bug fixes:
data/README.md CHANGED
@@ -11,14 +11,13 @@ Ruby D-Bus is a pure Ruby library for writing clients and services for D-Bus.
11
11
  [![Coverage Status][CS img]][Coverage Status]
12
12
 
13
13
  [Gem Version]: https://rubygems.org/gems/ruby-dbus
14
- [Build Status]: https://travis-ci.org/mvidner/ruby-dbus
15
- [travis pull requests]: https://travis-ci.org/mvidner/ruby-dbus/pull_requests
14
+ [Build Status]: https://github.com/mvidner/ruby-dbus/actions?query=branch%3Amaster
16
15
  [Dependency Status]: https://gemnasium.com/mvidner/ruby-dbus
17
16
  [Code Climate]: https://codeclimate.com/github/mvidner/ruby-dbus
18
17
  [Coverage Status]: https://coveralls.io/r/mvidner/ruby-dbus
19
18
 
20
19
  [GV img]: https://badge.fury.io/rb/ruby-dbus.png
21
- [BS img]: https://travis-ci.org/mvidner/ruby-dbus.png
20
+ [BS img]: https://github.com/mvidner/ruby-dbus/workflows/CI/badge.svg?branch=master
22
21
  [DS img]: https://gemnasium.com/mvidner/ruby-dbus.png
23
22
  [CC img]: https://codeclimate.com/github/mvidner/ruby-dbus.png
24
23
  [CS img]: https://coveralls.io/repos/mvidner/ruby-dbus/badge.png?branch=master
@@ -32,7 +31,6 @@ via [UPower](http://upower.freedesktop.org/docs/UPower.html#UPower:OnBattery)
32
31
  sysbus = DBus.system_bus
33
32
  upower_service = sysbus["org.freedesktop.UPower"]
34
33
  upower_object = upower_service["/org/freedesktop/UPower"]
35
- upower_object.introspect
36
34
  upower_interface = upower_object["org.freedesktop.UPower"]
37
35
  on_battery = upower_interface["OnBattery"]
38
36
  if on_battery
@@ -43,7 +41,7 @@ via [UPower](http://upower.freedesktop.org/docs/UPower.html#UPower:OnBattery)
43
41
 
44
42
  ## Requirements
45
43
 
46
- - Ruby 2.0 or newer.
44
+ - Ruby 2.1 or newer.
47
45
 
48
46
 
49
47
  ## Installation
data/Rakefile CHANGED
@@ -9,6 +9,12 @@ begin
9
9
  rescue LoadError
10
10
  nil
11
11
  end
12
+ begin
13
+ require "yard"
14
+ rescue LoadError
15
+ nil
16
+ end
17
+
12
18
  require "packaging"
13
19
 
14
20
  Packaging.configuration do |conf|
@@ -29,7 +35,7 @@ task test: :spec
29
35
 
30
36
  RSpec::Core::RakeTask.new("bare:spec")
31
37
 
32
- %w(spec).each do |tname|
38
+ ["spec"].each do |tname|
33
39
  desc "Run bare:#{tname} in the proper environment"
34
40
  task tname do |_t|
35
41
  cd "spec/tools" do
@@ -38,12 +44,6 @@ RSpec::Core::RakeTask.new("bare:spec")
38
44
  end
39
45
  end
40
46
 
41
- if ENV["TRAVIS"]
42
- require "coveralls/rake/task"
43
- Coveralls::RakeTask.new
44
- task default: "coveralls:push"
45
- end
46
-
47
47
  # remove tarball implementation and create gem for this gemfile
48
48
  Rake::Task[:tarball].clear
49
49
 
@@ -68,4 +68,22 @@ namespace :doc do
68
68
  end
69
69
  end
70
70
 
71
- RuboCop::RakeTask.new if Object.const_defined? :RuboCop
71
+ if Object.const_defined? :RuboCop
72
+ if RUBY_VERSION.start_with?("2.")
73
+ RuboCop::RakeTask.new
74
+ else
75
+ desc "Run RuboCop (dummy)"
76
+ task :rubocop do
77
+ warn "The code is not adapted to recent RuboCop yet,\n" \
78
+ "and the old one no longer works with Ruby 3.x.\n" \
79
+ "Switch back to Ruby 2.x to run it."
80
+ end
81
+ end
82
+ else
83
+ desc "Run RuboCop (dummy)"
84
+ task :rubocop do
85
+ warn "RuboCop not installed"
86
+ end
87
+ end
88
+
89
+ YARD::Rake::YardocTask.new if Object.const_defined? :YARD
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.0
1
+ 0.17.0
data/doc/Reference.md CHANGED
@@ -179,7 +179,7 @@ If the signature expects a Variant
179
179
  ISSUE: using something else than cryptic signatures is even more painful
180
180
  than remembering the signatures!
181
181
 
182
- foo_i["Bar"] = DBus.variant("au", [0, 1, 1, 2, 3, 5, 8])
182
+ `foo_i["Bar"] = DBus.variant("au", [0, 1, 1, 2, 3, 5, 8])`
183
183
 
184
184
  2. Other values are tried to fit one of these:
185
185
  Boolean, Double, Array of Variants, Hash of String keyed Variants,
@@ -244,14 +244,97 @@ When you want to provide a DBus API.
244
244
  (check that client and service side have their counterparts)
245
245
 
246
246
  ### Basic
247
+
247
248
  #### Exporting a Method
249
+
248
250
  ##### Interfaces
251
+
249
252
  ##### Methods
253
+
250
254
  ##### Bus Names
255
+
251
256
  ##### Errors
257
+
252
258
  #### Exporting Properties
259
+
260
+ Similar to plain Ruby attributes, declared with
261
+
262
+ - {https://docs.ruby-lang.org/en/3.1/Module.html#method-i-attr_accessor attr_accessor}
263
+ - {https://docs.ruby-lang.org/en/3.1/Module.html#method-i-attr_reader attr_reader}
264
+ - {https://docs.ruby-lang.org/en/3.1/Module.html#method-i-attr_writer attr_writer}
265
+
266
+ These methods declare the attributes and export them as properties:
267
+
268
+ - {DBus::Object.dbus_attr_accessor}
269
+ - {DBus::Object.dbus_attr_reader}
270
+ - {DBus::Object.dbus_attr_writer}
271
+
272
+ For making properties out of Ruby methods (which are not attributes), use:
273
+
274
+ - {DBus::Object.dbus_accessor}
275
+ - {DBus::Object.dbus_reader}
276
+ - {DBus::Object.dbus_writer}
277
+
278
+ Note that the properties are declared in the Ruby naming convention with
279
+ `snake_case` and D-Bus sees them `CamelCased`. Use the `dbus_name` argument
280
+ for overriding this.
281
+
282
+  
283
+
284
+ class Note < DBus::Object
285
+ dbus_interface "net.vidner.Example.Properties" do
286
+ # A read-write property "Title",
287
+ # with `title` and `title=` accessing @title.
288
+ dbus_attr_accessor :title, DBus::Type::STRING
289
+
290
+ # A read-only property "Author"
291
+ # (type specified via DBus signature)
292
+ # with `author` reading `@author`
293
+ dbus_attr_reader :author, "s"
294
+
295
+ # A read-only property `Clock`
296
+ def clock
297
+ Time.now.to_s
298
+ end
299
+ dbus_reader :clock, "s"
300
+
301
+ # Name mapping: `CreationTime`
302
+ def creation_time
303
+ "1993-01-01 00:00:00 +0100"
304
+ end
305
+ dbus_reader :creation_time, "s"
306
+
307
+ dbus_attr_accessor :book_volume, DBus::Type::VARIANT, dbus_name: "Volume"
308
+ end
309
+
310
+ dbus_interface "net.vidner.Example.Audio" do
311
+ dbus_attr_accessor :speaker_volume, DBus::Type::BYTE, dbus_name: "Volume"
312
+ end
313
+
314
+ # Must assign values because `nil` would crash our connection
315
+ def initialize(opath)
316
+ super
317
+ @title = "Ahem"
318
+ @author = "Martin"
319
+ @book_volume = 1
320
+ @speaker_volume = 11
321
+ end
322
+ end
323
+
324
+ obj = Note.new("/net/vidner/Example/Properties")
325
+
326
+ bus = DBus::SessionBus.instance
327
+ service = bus.request_service("net.vidner.Example")
328
+ service.export(obj)
329
+
330
+ main = DBus::Main.new
331
+ main << bus
332
+ main.run
333
+
253
334
  ### Advanced
335
+
254
336
  #### Inheritance
337
+
255
338
  #### Names
256
339
 
257
340
  Specification Conformance
@@ -4,6 +4,9 @@ if ARGV[0].nil?
4
4
  exit
5
5
  end
6
6
 
7
+ base_url = "https://github.com/mvidner/ruby-dbus/blob/master/"
8
+ base_url += ARGV[0].gsub("../", "")
9
+
7
10
  File.open(ARGV[0]) do |f|
8
11
  title = nil
9
12
  setup = ""
@@ -20,7 +23,9 @@ File.open(ARGV[0]) do |f|
20
23
  setup = example
21
24
  else
22
25
  File.open("#{basename}.rb", "w") do |e|
26
+ anchor = title.downcase.gsub(/ +/, "-")
23
27
  e.write setup
28
+ e.write "# #{base_url}##{anchor}\n"
24
29
  e.write example
25
30
  e.chmod(0o755)
26
31
  end
data/examples/gdbus/gdbus CHANGED
@@ -119,25 +119,26 @@ class DBusUI
119
119
  model = Gtk::ListStore.new(String, String, DBus::Method,
120
120
  DBus::ProxyObjectInterface)
121
121
  @methsigtreeview.model = model
122
- if selected
123
- if (intf = selected[1])
124
- intf.methods.keys.sort.each do |mi|
125
- m = intf.methods[mi]
126
- subiter = model.append
127
- subiter[0] = beautify_method(m)
128
- subiter[1] = "M"
129
- subiter[2] = m
130
- subiter[3] = intf
131
- end
132
- intf.signals.keys.sort.each do |mi|
133
- m = intf.signals[mi]
134
- subiter = model.append
135
- subiter[0] = beautify_method(m)
136
- subiter[1] = "S"
137
- subiter[2] = m
138
- subiter[3] = intf
139
- end
140
- end
122
+ return unless selected
123
+
124
+ intf = selected[1]
125
+ return unless intf
126
+
127
+ intf.methods.keys.sort.each do |mi|
128
+ m = intf.methods[mi]
129
+ subiter = model.append
130
+ subiter[0] = beautify_method(m)
131
+ subiter[1] = "M"
132
+ subiter[2] = m
133
+ subiter[3] = intf
134
+ end
135
+ intf.signals.keys.sort.each do |mi|
136
+ m = intf.signals[mi]
137
+ subiter = model.append
138
+ subiter[0] = beautify_method(m)
139
+ subiter[1] = "S"
140
+ subiter[2] = m
141
+ subiter[3] = intf
141
142
  end
142
143
  end
143
144
 
@@ -226,7 +227,7 @@ class DBusUI
226
227
 
227
228
  def introspect_services(model, bus)
228
229
  el = @introspect_array.shift
229
- if !(el =~ /^:/)
230
+ if el !~ /^:/
230
231
  iter = model.append(nil)
231
232
  iter[0] = el
232
233
  puts "introspecting: #{el}"
@@ -14,7 +14,7 @@ player.test_variant(["s", "coucou"])
14
14
  player.on_signal("SomethingJustHappened") do |u, v|
15
15
  puts "SomethingJustHappened: #{u} #{v}"
16
16
  end
17
- player.hello("8=======D", "(_._)")
17
+ player.hello("Hey", "there!")
18
18
  p player["org.ruby.AnotherInterface"].Reverse("Hello world!")
19
19
 
20
20
  main = DBus::Main.new
data/lib/dbus/auth.rb CHANGED
@@ -73,7 +73,7 @@ module DBus
73
73
  path = File.join(ENV["HOME"], ".dbus-keyrings", context)
74
74
  DBus.logger.debug "path: #{path.inspect}"
75
75
  File.foreach(path) do |line|
76
- if line.index(id) == 0
76
+ if line.start_with?(id)
77
77
  # Right line of file, read cookie
78
78
  cookie = line.split(" ")[2].chomp
79
79
  DBus.logger.debug "cookie: #{cookie.inspect}"
@@ -87,14 +87,14 @@ module DBus
87
87
  return response
88
88
  end
89
89
  end
90
+ return if @retries <= 0
91
+
90
92
  # a little rescue magic
91
- unless @retries <= 0
92
- puts "ERROR: Could not auth, will now exit."
93
- puts "ERROR: Unable to locate cookie, retry in 1 second."
94
- @retries -= 1
95
- sleep 1
96
- data(hexdata)
97
- end
93
+ puts "ERROR: Could not auth, will now exit."
94
+ puts "ERROR: Unable to locate cookie, retry in 1 second."
95
+ @retries -= 1
96
+ sleep 1
97
+ data(hexdata)
98
98
  end
99
99
 
100
100
  # encode plain to hex
data/lib/dbus/bus.rb CHANGED
@@ -17,7 +17,7 @@ require "singleton"
17
17
  # Module containing all the D-Bus modules and classes.
18
18
  module DBus
19
19
  # This represents a remote service. It should not be instantiated directly
20
- # Use Bus::service()
20
+ # Use {Connection#service}
21
21
  class Service
22
22
  # The service name.
23
23
  attr_reader :name
@@ -28,7 +28,7 @@ module DBus
28
28
 
29
29
  # Create a new service with a given _name_ on a given _bus_.
30
30
  def initialize(name, bus)
31
- @name = name
31
+ @name = BusName.new(name)
32
32
  @bus = bus
33
33
  @root = Node.new("/")
34
34
  end
@@ -148,20 +148,22 @@ module DBus
148
148
 
149
149
  # Return an XML string representation of the node.
150
150
  # It is shallow, not recursing into subnodes
151
- def to_xml
151
+ # @param node_opath [String]
152
+ def to_xml(node_opath)
152
153
  xml = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
153
154
  "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
154
- <node>
155
155
  '
156
+ xml += "<node name=\"#{node_opath}\">\n"
156
157
  each_pair do |k, _v|
157
- xml += "<node name=\"#{k}\" />"
158
+ xml += " <node name=\"#{k}\" />\n"
158
159
  end
159
160
  if @object
160
161
  @object.intfs.each_pair do |_k, v|
161
- xml += %(<interface name="#{v.name}">\n)
162
+ xml += " <interface name=\"#{v.name}\">\n"
162
163
  v.methods.each_value { |m| xml += m.to_xml }
163
164
  v.signals.each_value { |m| xml += m.to_xml }
164
- xml += "</interface>\n"
165
+ v.properties.each_value { |m| xml += m.to_xml }
166
+ xml += " </interface>\n"
165
167
  end
166
168
  end
167
169
  xml += "</node>"
@@ -387,7 +389,7 @@ module DBus
387
389
  # introspect in synchronous !
388
390
  data = introspect_data(dest, path)
389
391
  pof = DBus::ProxyObjectFactory.new(data, self, dest, path)
390
- return pof.build
392
+ pof.build
391
393
  else
392
394
  introspect_data(dest, path) do |async_data|
393
395
  yield(DBus::ProxyObjectFactory.new(async_data, self, dest, path).build)
@@ -458,6 +460,9 @@ module DBus
458
460
  retm = wait_for_message
459
461
  process(retm)
460
462
  end
463
+ rescue EOFError
464
+ new_err = DBus::Error.new("Connection dropped after we sent #{m.inspect}")
465
+ raise new_err
461
466
  end
462
467
 
463
468
  # @api private
@@ -529,7 +534,8 @@ module DBus
529
534
  m.member == "Introspect"
530
535
  reply = Message.new(Message::METHOD_RETURN).reply_to(m)
531
536
  reply.sender = @unique_name
532
- reply.add_param(Type::STRING, node.to_xml)
537
+ xml = node.to_xml(m.path)
538
+ reply.add_param(Type::STRING, xml)
533
539
  @message_queue.push(reply)
534
540
  else
535
541
  obj = node.object
@@ -538,7 +544,8 @@ module DBus
538
544
  end
539
545
  when DBus::Message::SIGNAL
540
546
  # the signal can match multiple different rules
541
- @signal_matchrules.each do |mrs, slot|
547
+ # clone to allow new signale handlers to be registered
548
+ @signal_matchrules.dup.each do |mrs, slot|
542
549
  if DBus::MatchRule.new.from_s(mrs).match(m)
543
550
  slot.call(m)
544
551
  end
@@ -562,6 +569,11 @@ module DBus
562
569
  # @api private
563
570
  # Emit a signal event for the given _service_, object _obj_, interface
564
571
  # _intf_ and signal _sig_ with arguments _args_.
572
+ # @param service [Service]
573
+ # @param obj [DBus::Object]
574
+ # @param intf [Interface]
575
+ # @param sig [Signal]
576
+ # @param args arguments for the signal
565
577
  def emit(service, obj, intf, sig, *args)
566
578
  m = Message.new(DBus::Message::SIGNAL)
567
579
  m.path = obj.path
@@ -664,7 +676,7 @@ module DBus
664
676
  # (for Unix-socket) unix:path=/tmp/my_funky_bus_socket
665
677
  #
666
678
  # you'll need to take care about authentification then, more info here:
667
- # http://github.com/pangdudu/ruby-dbus/blob/master/README.rdoc
679
+ # https://gitlab.com/pangdudu/ruby-dbus/-/blob/master/README.rdoc
668
680
  class RemoteBus < Connection
669
681
  # Get the remote bus.
670
682
  def initialize(socket_name)
@@ -0,0 +1,27 @@
1
+ # This file is part of the ruby-dbus project
2
+ # Copyright (C) 2019 Martin Vidner
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License, version 2.1 as published by the Free Software Foundation.
7
+ # See the file "COPYING" for the exact licensing terms.
8
+
9
+ module DBus
10
+ # A {::String} that validates at initialization time
11
+ # @see https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus
12
+ class BusName < String
13
+ # @raise Error if not a valid bus name
14
+ def initialize(s)
15
+ unless self.class.valid?(s)
16
+ raise DBus::Error, "Invalid bus name #{s.inspect}"
17
+ end
18
+ super
19
+ end
20
+
21
+ def self.valid?(s)
22
+ s.size <= 255 &&
23
+ (s =~ /\A:[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+)+\z/ ||
24
+ s =~ /\A[A-Za-z_-][A-Za-z0-9_-]*(\.[A-Za-z_-][A-Za-z0-9_-]*)+\z/)
25
+ end
26
+ end
27
+ end
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
1
2
  # copied from activesupport/core_ext from Rails, MIT license
2
- # https://github.com/rails/rails/tree/5aa869861c192daceafe3a3ee50eb93f5a2b7bd2/activesupport/lib/active_support/core_ext
3
- require 'dbus/core_ext/kernel/singleton_class'
4
- require 'dbus/core_ext/module/remove_method'
5
- require 'dbus/core_ext/array/extract_options'
3
+ # https://github.com/rails/rails/tree/9794e85351243cac6d4e78adaba634b8e4ecad0a/activesupport/lib/active_support/core_ext
4
+
5
+ require_relative "../module/redefine_method"
6
6
 
7
7
  class Class
8
8
  # Declare a class-level attribute whose value is inheritable by subclasses.
9
9
  # Subclasses can change their own value and it will not impact parent class.
10
10
  #
11
+ # ==== Examples
12
+ #
11
13
  # class Base
12
- # class_attribute :setting
14
+ # my_class_attribute :setting
13
15
  # end
14
16
  #
15
17
  # class Subclass < Base
@@ -22,14 +24,14 @@ class Class
22
24
  # Base.setting # => true
23
25
  #
24
26
  # In the above case as long as Subclass does not assign a value to setting
25
- # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt>
27
+ # by performing <tt>Subclass.setting = _something_</tt>, <tt>Subclass.setting</tt>
26
28
  # would read value assigned to parent class. Once Subclass assigns a value then
27
29
  # the value assigned by Subclass would be returned.
28
30
  #
29
31
  # This matches normal Ruby method inheritance: think of writing an attribute
30
32
  # on a subclass as overriding the reader method. However, you need to be aware
31
33
  # when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
32
- # In such cases, you don't want to do changes in places but use setters:
34
+ # In such cases, you don't want to do changes in place. Instead use setters:
33
35
  #
34
36
  # Base.setting = []
35
37
  # Base.setting # => []
@@ -59,39 +61,25 @@ class Class
59
61
  # object.setting = false
60
62
  # object.setting # => false
61
63
  # Base.setting # => true
62
- #
63
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
64
- #
65
- # object.setting # => NoMethodError
66
- # object.setting? # => NoMethodError
67
- #
68
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
69
- #
70
- # object.setting = false # => NoMethodError
71
- #
72
- # To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
73
- def class_attribute(*attrs)
74
- options = attrs.extract_options!
75
- instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
76
- instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
77
- instance_predicate = options.fetch(:instance_predicate, true)
64
+ def my_class_attribute(*attrs)
65
+ instance_reader = true
66
+ instance_writer = true
78
67
 
79
68
  attrs.each do |name|
69
+ singleton_class.silence_redefinition_of_method(name)
80
70
  define_singleton_method(name) { nil }
81
- define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
82
71
 
83
- ivar = "@#{name}"
72
+ ivar = "@#{name}".to_sym
84
73
 
74
+ singleton_class.silence_redefinition_of_method("#{name}=")
85
75
  define_singleton_method("#{name}=") do |val|
86
76
  singleton_class.class_eval do
87
- remove_possible_method(name)
88
- define_method(name) { val }
77
+ redefine_method(name) { val }
89
78
  end
90
79
 
91
80
  if singleton_class?
92
81
  class_eval do
93
- remove_possible_method(name)
94
- define_method(name) do
82
+ redefine_method(name) do
95
83
  if instance_variable_defined? ivar
96
84
  instance_variable_get ivar
97
85
  else
@@ -104,26 +92,20 @@ class Class
104
92
  end
105
93
 
106
94
  if instance_reader
107
- remove_possible_method name
108
- define_method(name) do
95
+ redefine_method(name) do
109
96
  if instance_variable_defined?(ivar)
110
97
  instance_variable_get ivar
111
98
  else
112
99
  self.class.public_send name
113
100
  end
114
101
  end
115
- define_method("#{name}?") { !!public_send(name) } if instance_predicate
116
102
  end
117
103
 
118
- attr_writer name if instance_writer
119
- end
120
- end
121
-
122
- private
123
-
124
- unless respond_to?(:singleton_class?)
125
- def singleton_class?
126
- ancestors.first != self
104
+ if instance_writer
105
+ redefine_method("#{name}=") do |val|
106
+ instance_variable_set ivar, val
107
+ end
127
108
  end
128
109
  end
110
+ end
129
111
  end