ruby-dbus-0.13.0/ 0000755 0000041 0000041 00000000000 13004252346 013536 5 ustar www-data www-data ruby-dbus-0.13.0/Rakefile 0000644 0000041 0000041 00000003327 13004252346 015210 0 ustar www-data www-data #! /usr/bin/env ruby
require "rake"
require "fileutils"
include FileUtils
require "tmpdir"
require "rspec/core/rake_task"
begin
require "rubocop/rake_task"
rescue LoadError
nil
end
require "packaging"
Packaging.configuration do |conf|
conf.obs_project = "devel:languages:ruby:extensions"
conf.obs_target = "openSUSE_Tumbleweed"
conf.package_name = "rubygem-ruby-dbus"
conf.obs_sr_project = "openSUSE:Factory"
conf.skip_license_check << %r{^[^/]*$}
conf.skip_license_check << %r{^(doc|examples|spec)/.*}
# "Ruby on Rails is released under the MIT License."
# but the files are missing copyright headers
conf.skip_license_check << %r{^lib/dbus/core_ext/}
end
desc "Default: run specs in the proper environment"
task default: [:spec, :rubocop]
task test: :spec
RSpec::Core::RakeTask.new("bare:spec")
%w(spec).each do |tname|
desc "Run bare:#{tname} in the proper environment"
task tname do |_t|
cd "spec/tools" do
sh "./test_env rake bare:#{tname}"
end
end
end
if ENV["TRAVIS"]
require "coveralls/rake/task"
Coveralls::RakeTask.new
task default: "coveralls:push"
end
# remove tarball implementation and create gem for this gemfile
Rake::Task[:tarball].clear
desc "Build a package from a clone of the local Git repo"
task :tarball do |_t|
Dir.mktmpdir do |temp|
sh "git clone . #{temp}"
cd temp do
sh "gem build ruby-dbus.gemspec"
end
sh "rm -f package/*.gem"
cp Dir.glob("#{temp}/*.gem"), "package"
end
end
namespace :doc do
desc "Extract code examples from doc/Reference.md to examples/doc"
task :examples do
cd "examples/doc" do
sh "./_extract_examples ../../doc/Reference.md"
end
end
end
RuboCop::RakeTask.new if Object.const_defined? :RuboCop
ruby-dbus-0.13.0/NEWS.md 0000644 0000041 0000041 00000024600 13004252346 014636 0 ustar www-data www-data # Ruby D-Bus NEWS
## Unreleased
## Ruby D-Bus 0.13.0 - 2016-09-21
Bug fixes:
* It is no longer required to explicitly call ProxyObject#introspect,
it will be done automatically once ([#28][]).
Requirements:
* Introduced RuboCop to keep a consistent coding style.
* Replaced Gemfile.ci with a regular Gemfile.
[#28]: http://github.com/mvidner/ruby-dbus/issue/28
## Ruby D-Bus 0.12.0 - 2016-09-12
API:
* Added proxy objects whose methods return single values instead of arrays
(use Service#[] instead of Service#object; [#30][]).
Requirements:
* Require ruby 2.0.0, stopped supporting 1.9.3.
[#30]: http://github.com/mvidner/ruby-dbus/issue/30
## Ruby D-Bus 0.11.2 - 2016-09-11
Bug fixes:
* Fixed reading a quoted session bus address, as written by dbus-1.10.10
([#62][], Yasuhiro Asaka)
[#62]: https://github.com/mvidner/ruby-dbus/pull/62
## Ruby D-Bus 0.11.1 - 2016-05-12
Bug fixes:
* Fix default path finding on FreeBSD (Greg)
* Service#unexport fixed to really return the unexported object
Requirements:
* made tests compatible with RSpec 3
## Ruby D-Bus 0.11.0 - 2014-02-17
API:
* Connection: split off MessageQueue, marked other methods as private.
Requirements:
* converted tests to RSpec, rather mechanically for now
## Ruby D-Bus 0.10.0 - 2014-01-10
Bug fixes:
* fixed "Interfaces added with singleton_class.instance_eval aren't
exported" ([#22][], by miaoufkirsh)
Requirements:
* Require ruby 1.9.3, stopped supporting 1.8.7.
[#22]: https://github.com/mvidner/ruby-dbus/issue/22
## Ruby D-Bus 0.9.3 - 2014-01-02
Bug fixes:
* re-added COPYING, NEWS, README.md to the gem ([#47][],
by Cédric Boutillier)
Packaging:
* use packaging_rake_tasks
[#47]: https://github.com/mvidner/ruby-dbus/issue/47
## Ruby D-Bus 0.9.2 - 2013-05-08
Features:
* Ruby strings can be passed where byte arrays ("ay") are expected
([#40][], by Jesper B. Rosenkilde)
Bug fixes:
* Fixed accessing ModemManager properties ([#41][], reported
by Ernest Bursa). MM introspection produces two elements
for a single interface; merge them.
[#40]: https://github.com/mvidner/ruby-dbus/issue/40
[#41]: https://github.com/mvidner/ruby-dbus/issue/41
## Ruby D-Bus 0.9.1 - 2013-04-23
Bug fixes:
* Prefer /etc/machine-id to /var/lib/dbus/machine-id
when DBUS_SESSION_BUS_ADDRESS is unset ([#39][], by WU Jun).
[#39]: https://github.com/mvidner/ruby-dbus/issue/39
## Ruby D-Bus 0.9.0 - 2012-11-06
Features:
* When calling methods, the interface can be left unspecified if unambiguous
(Damiano Stoffie)
* YARD documentation, Reference.md
Bug fixes:
* Introspection attribute "direction" can be omitted
as allowed by the specification (Noah Meyerhans).
* ProxyObjectInterface#on_signal no longer needs the "bus" parameter
([#31][], by Damiano Stoffie)
[#31]: https://github.com/mvidner/ruby-dbus/issue/31
## Ruby D-Bus 0.8.0 - 2012-09-20
Features:
* Add Anonymous authentication ([#27][], by Walter Brebels).
* Use Nokogiri for XML parsing when available ([#24][], by Geoff Youngs).
Bug fixes:
* Use SCM_CREDS authentication only on FreeBSD, not on OpenBSD ([#21][],
reported by Adde Nilsson).
* Recognize signature "h" (UNIX_FD) used eg. by Upstart ([#23][],
by Bernd Ahlers).
* Find the session bus also via launchd, on OS X ([#20][], reported
by Paul Sturgess).
Other:
* Now doing continuous integration with Travis:
http://travis-ci.org/#!/mvidner/ruby-dbus
[#20]: https://github.com/mvidner/ruby-dbus/issue/20
[#21]: https://github.com/mvidner/ruby-dbus/issue/21
[#23]: https://github.com/mvidner/ruby-dbus/issue/23
[#24]: https://github.com/mvidner/ruby-dbus/issue/24
[#27]: https://github.com/mvidner/ruby-dbus/issue/27
## Ruby D-Bus 0.7.2 - 2012-04-05
A brown-paper-bag release.
Bug fixes:
* Fixed "undefined local variable or method `continue'" in
DBus::Main#run when a service becomes idle (by Ravil Bayramgalin)
## Ruby D-Bus 0.7.1 - 2012-04-04
Bug fixes:
* Fixed calling asynchronous methods on the default interface ([#13][],
by Eugene Korbut).
* Fixed Main#quit to really quit the loop (by Josef Reidinger)
* Unbundled files from Active Support (by Bohuslav Kabrda)
[#13]: https://github.com/mvidner/ruby-dbus/issue/13
## Ruby D-Bus 0.7.0 - 2011-07-26
Features:
* Added ASystemBus and ASessionBus, non-singletons useful in tests
and threads.
Bug fixes:
* Fixed handling of multibyte strings ([#8][], by Takayuki YAMAGUCHI).
* Allow reopening of a dbus_interface declaration ([#9][], by T. YAMAGUCHI).
* Fixed ruby-1.9.2 compatibility again ([#12][]).
* Fixed authentication on BSD ([#11][], by Jonathan Walker)
* Fixed exiting a nested event loop for synchronous calls
(reported by Timo Warns).
* Fixed introspection calls leaking reply handlers.
* "rake test" now works, doing what was called "rake env:test"
[#8]: https://github.com/mvidner/ruby-dbus/issue/8
[#9]: https://github.com/mvidner/ruby-dbus/issue/9
[#11]: https://github.com/mvidner/ruby-dbus/issue/11
[#12]: https://github.com/mvidner/ruby-dbus/issue/12
## Ruby D-Bus 0.6.0 - 2010-12-11
Features:
* Clients can access properties conveniently ([T#28][]).
Bug fixes:
* Service won't crash whan handling an unknown method or interface ([T#31][]).
* Don't send an invalid error name when it originates from a NameError.
[T#28]: https://trac.luon.net/ruby-dbus/ticket/28
[T#31]: https://trac.luon.net/ruby-dbus/ticket/31
## Ruby D-Bus 0.5.0 - 2010-11-07
Features:
* Better binding of Ruby Exceptions to D-Bus Errors.
* Converted the package to a Gem ([#6][]).
* Converted the tutorial from Webgen to Markdown.
Bug fixes:
* Don't pass file descriptors to subprocesses.
* Fixed InterfaceElement::validate_name ([T#38][], by Herwin Weststrate).
* Fixed a typo in InvalidDestinationName description ([T#40][]).
[#6]: https://github.com/mvidner/ruby-dbus/issue/6
[T#38]: https://trac.luon.net/ruby-dbus/ticket/38
[T#40]: https://trac.luon.net/ruby-dbus/ticket/40
## Ruby D-Bus 0.4.0 - 2010-08-20
Features:
* TCP transport (by pangdudu)
* Enabled test code coverage report (rcov)
Bug fixes:
* Classes should not share all interfaces ([T#36][]/[#5][])
* Ruby 1.9 compatibility ([T#37][], by Myra Nelson)
[#5]: https://github.com/mvidner/ruby-dbus/issue/5
[T#36]: https://trac.luon.net/ruby-dbus/ticket/36
[T#37]: https://trac.luon.net/ruby-dbus/ticket/37
## Ruby D-Bus 0.3.1 - 2010-07-22
Bug fixes:
* Many on_signal could cause DBus.Error.LimitsExceeded [bsc#617350][]).
Don't add a match rule that already exists, enable removing match
rules. Now only one handler for a rule is called (but it is possible
for one signal to match more rules). This reverts the half-fix done
to fix [#3][]
* Re-added InterfaceElement#add_param for compatibility.
* Handle more ways which tell us that a bus connection has died.
[#3]: https://github.com/mvidner/ruby-dbus/issue/3
[bsc#617350]: https://bugzilla.novell.com/show_bug.cgi?id=617350
## Ruby D-Bus 0.3.0 - 2010-03-28
Bug fixes:
* Fixed "undefined method `get_node' for nil:NilClass"
on Ubuntu Karmic ([T#34][]).
* Get the session bus address even if unset in ENV ([#4][]).
* Improved exceptions a bit:
UndefinedInterface, InvalidMethodName, NoMethodError, no RuntimeException
These are by Klaus Kaempf:
* Make the signal dispatcher call all handlers ([#3][]).
* Run on Ruby < 1.8.7 ([#2][]).
* Avoid needless DBus::IncompleteBufferException ([T#33][]).
* Don't ignore DBus Errors in request_service, raise them ([T#32][]).
[#2]: https://github.com/mvidner/ruby-dbus/issue/2
[#3]: https://github.com/mvidner/ruby-dbus/issue/3
[#4]: https://github.com/mvidner/ruby-dbus/issue/4
[T#32]: https://trac.luon.net/ruby-dbus/ticket/32
[T#33]: https://trac.luon.net/ruby-dbus/ticket/33
[T#34]: https://trac.luon.net/ruby-dbus/ticket/34
Features:
* Automatic signature inference for variants.
* Introduced FormalParameter where a plain pair had been used.
## Ruby D-Bus 0.2.12 - 2010-01-24
Bug fixes:
* Fixed a long-standing bug where a service activated by the bus
would fail with "undefined method `get_node' for nil:NilClass"
([T#25][] and [T#29][]).
[T#25]: https://trac.luon.net/ruby-dbus/ticket/25
[T#29]: https://trac.luon.net/ruby-dbus/ticket/29
## Ruby D-Bus 0.2.11 - 2009-11-12
Features:
* Added DBus::Service#unexport (da1l6).
Bug fixes:
* Return org.freedesktop.DBus.Error.UnknownObject instead of crashing
([T#31][]).
* Rescue exceptions in dbus_methods and reply with DBus errors instead of
crashing (da1l6).
* Better exception messages when sending nil, or mismatched structs.
* Call mktemp without --tmpdir, to build on older distros.
[T#31]: https://trac.luon.net/ruby-dbus/ticket/31
## Ruby D-Bus 0.2.10 - 2009-09-10
Bug fixes:
* DBus::Service.exists? fixed (Murat Demirten).
* Ruby 1.9 fixes (Jedediah Smith).
* Fixed an endless sleep in DBus::Main.run ([bsc#537401][]).
* Added details to PacketMarshaller exceptions ([bsc#538050][]).
[bsc#537401]: https://bugzilla.novell.com/show_bug.cgi?id=537401
[bsc#538050]: https://bugzilla.novell.com/show_bug.cgi?id=538050
## Ruby D-Bus "I'm not dead" 0.2.9 - 2009-08-26
Thank you to Paul and Arnaud for starting the project. I, Martin
Vidner, am continuing with it on GitHub.
* Fixed passing an array through a variant (no ticket).
* Fixed marshalling "av" ([T#30][]).
* Fixed variant alignment ([T#27][]).
* Added DBus::Main.quit.
* Mention the DBus interface in a NameError for an unknown method.
* Fixed ruby-1.9 "warning: default `to_a' will be obsolete".
* Added Rakefile and gemspec.
[T#27]: https://trac.luon.net/ruby-dbus/ticket/27
[T#30]: https://trac.luon.net/ruby-dbus/ticket/30
## Ruby D-Bus "Thanks for all the fish" 0.2.1 - 2007-12-29
More bugfixes, mostly supplied by users supplying us with patches. Thanks!
* Support for new types added:
- dict (courtesy of Drake Wilson);
- double (courtesy of Patrick Sissons);
- variant.
* Improved exception raise support (courtesy of Sjoerd Simons,
Patrick Sissons).
* Some polish (removed debug output, solved unnecessary warnings).
* Documentation updates, example fixes and updates.
## Ruby D-Bus "Almost live from DebConf 7" 0.2.0 - 2007-06-02
Again a bugfix release, also meant to be the public release
for exploratory purposes. New in 0.2.0:
* Complete tutorial revamp.
* Relicensed to the LGPL.
## Ruby D-Bus "Release Often" 0.1.1 - 2007-04-23
Bugfix release. Fixes hardcoded string for requesting bus names,
found by Rudi Cilibrasi.
## Ruby D-Bus "Happy Birthday Paul" 0.1.0 - 2007-04-17
First release. Supports most of D-Bus' features.
ruby-dbus-0.13.0/examples/ 0000755 0000041 0000041 00000000000 13004252346 015354 5 ustar www-data www-data ruby-dbus-0.13.0/examples/doc/ 0000755 0000041 0000041 00000000000 13004252346 016121 5 ustar www-data www-data ruby-dbus-0.13.0/examples/doc/_extract_examples 0000755 0000041 0000041 00000001360 13004252346 021556 0 ustar www-data www-data #!/usr/bin/env ruby
if ARGV[0].nil?
puts "Usage: #{$PROGRAM_NAME} file.md"
exit
end
File.open(ARGV[0]) do |f|
title = nil
setup = ""
example = ""
f.each_line do |line|
case line
when /^#+ *(.*)/
new_title = Regexp.last_match(1)
# write previous example
unless example.empty?
basename = title.downcase.gsub(/ +/, "_")
if basename == "setting_up"
setup = example
else
File.open("#{basename}.rb", "w") do |e|
e.write setup
e.write example
e.chmod(0o755)
end
end
end
# set new
title = new_title
example = ""
when /^ (.*)/
example << Regexp.last_match(1) << "\n"
end
end
end
ruby-dbus-0.13.0/examples/doc/README.md 0000644 0000041 0000041 00000000232 13004252346 017375 0 ustar www-data www-data This directory contains runnable examples
extracted from [the reference documentation](../../doc/Reference.md).
Run `rake doc:examples` to extract them.
ruby-dbus-0.13.0/examples/rhythmbox/ 0000755 0000041 0000041 00000000000 13004252346 017400 5 ustar www-data www-data ruby-dbus-0.13.0/examples/rhythmbox/playpause.rb 0000755 0000041 0000041 00000001005 13004252346 021727 0 ustar www-data www-data #!/usr/bin/env ruby
require "dbus"
bus = DBus::SessionBus.instance
# get a rb object
proxy = bus.introspect("org.gnome.Rhythmbox", "/org/gnome/Rhythmbox/Player")
proxyi = proxy["org.gnome.Rhythmbox.Player"]
# register for signals
mr = DBus::MatchRule.new
mr.type = "signal"
mr.interface = "org.gnome.Rhythmbox.Player"
mr.path = "/org/gnome/Rhythmbox/Player"
bus.add_match(mr) do |msg, first_param|
print msg.member + " "
puts first_param
end
proxyi.playPause(true)
main = DBus::Main.new
main << bus
main.run
ruby-dbus-0.13.0/examples/gdbus/ 0000755 0000041 0000041 00000000000 13004252346 016460 5 ustar www-data www-data ruby-dbus-0.13.0/examples/gdbus/gdbus.glade 0000644 0000041 0000041 00000010057 13004252346 020565 0 ustar www-data www-data
ruby-dbus-0.13.0/examples/gdbus/gdbus 0000755 0000041 0000041 00000016257 13004252346 017525 0 ustar www-data www-data #!/usr/bin/env ruby
#
# This is a quite complex example using internal lower level API.
# Not a good starting point, but might be usefull if you want to do tricky
# stuff.
# -- Arnaud
require "dbus"
require "gtk2"
ENABLE_SYSTEM = false
class MethodCallWindow
def initialize(pwindow, intf, meth)
@intf = intf
@meth = meth
@entries = []
@dialog = Gtk::Dialog.new(meth.name, pwindow,
Gtk::Dialog::MODAL | Gtk::Dialog::NO_SEPARATOR,
[Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK],
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
@meth.params.each do |param|
shbox = Gtk::HBox.new(true, 0)
label = Gtk::Label.new("#{param[0]} (#{param[1]})")
input = Gtk::Entry.new
@entries << input
shbox.pack_start(label, true, true, 0)
shbox.pack_start(input, true, true, 0)
@dialog.vbox.pack_start(shbox, true, true, 0)
@dialog.vbox.show_all
end
end
def run
on_ok if @dialog.run == Gtk::Dialog::RESPONSE_OK
@dialog.destroy
end
def on_ok
bus = @intf.object.bus
m = DBus::Message.new(DBus::Message::METHOD_CALL)
m.path = @intf.object.path
m.interface = @intf.name
m.destination = @intf.object.destination
m.member = @meth.name
m.sender = bus.unique_name
@meth.params.each_with_index do |param, idx|
entry = @entries[idx]
data = nil
case param[1]
when "u", "i"
data = entry.text.to_i
when "s"
data = entry.text
when /^a/
begin
data = eval(entry.text)
rescue
puts "Incorrect data: #{data}"
end
end
m.add_param(param[1], data)
end
bus.send_sync_or_async(m) do |retm|
if retm.is_a?(DBus::Error)
puts "Error: #{retm.inspect}"
else
puts "Method #{m.member} returns: #{retm.params.inspect}"
end
end
end
end
class DBusUI
def initialize
@glade = Gtk::Builder.new
@glade << "gdbus.glade"
@sessiontreeview = @glade.get_object("sessiontreeview")
setup_treeview_renderer(@sessiontreeview, "D-Bus Objects")
@sessiontreeview.selection.signal_connect("changed") do |selection|
on_treeview_selection_changed(selection)
end
@systemtreeview = @glade.get_object("systemtreeview")
setup_treeview_renderer(@systemtreeview, "D-Bus Objects")
@systemtreeview.selection.signal_connect("changed") do |selection|
on_treeview_selection_changed(selection)
end
@methsigtreeview = @glade.get_object("methsigtreeview")
# ierk
setup_methodview_renderer(@methsigtreeview)
@methsigtreeview.signal_connect("row-activated") do |view, path, column|
on_method_activated(view, path, column)
end
@window = @glade.get_object("window1")
@window.show_all
start_buses
end
def beautify_method(meth)
# Damn, this need to be rewritten :p
s = meth.name + "("
if meth.is_a?(DBus::Method)
s += (meth.params.collect { |a| "in #{a[0]}:#{a[1]}" } +
meth.rets.collect { |a| "out #{a[0]}:#{a[1]}" }).join(", ")
elsif meth.is_a?(DBus::Signal)
s += (meth.params.collect { |a| "in #{a[0]}:#{a[1]}" }).join(", ")
end
s += ")"
s
end
def on_treeview_selection_changed(selection)
selected = selection.selected
model = Gtk::ListStore.new(String, String, DBus::Method,
DBus::ProxyObjectInterface)
@methsigtreeview.model = model
if selected
if (intf = selected[1])
intf.methods.keys.sort.each do |mi|
m = intf.methods[mi]
subiter = model.append
subiter[0] = beautify_method(m)
subiter[1] = "M"
subiter[2] = m
subiter[3] = intf
end
intf.signals.keys.sort.each do |mi|
m = intf.signals[mi]
subiter = model.append
subiter[0] = beautify_method(m)
subiter[1] = "S"
subiter[2] = m
subiter[3] = intf
end
end
end
end
def on_method_activated(view, path, _column)
name = view.model.get_iter(path)[0]
puts "Clicked on: #{name.inspect}"
type = view.model.get_iter(path)[1]
if type == "M"
method = view.model.get_iter(path)[2]
intf = view.model.get_iter(path)[3]
MethodCallWindow.new(@window, intf, method).run
elsif type == "S"
signal = view.model.get_iter(path)[2]
intf = view.model.get_iter(path)[3]
mr = DBus::MatchRule.new.from_signal(intf, signal)
puts "*** Registering matchrule: #{mr} ***"
intf.object.bus.add_match(mr) do |sig|
puts "Got #{sig.member}(#{sig.params.join(",")})"
end
end
end
def on_sessiontreeview_row_activated(view, path, _column)
name = view.model.get_iter(path)[0]
puts "Clicked on: #{name.inspect}"
end
def on_window_delete_event(_window, _event)
Gtk.main_quit
end
def setup_methodview_renderer(treeview)
renderer = Gtk::CellRendererText.new
_col_offset = treeview.insert_column(-1, "T", renderer, "text" => 1)
col_offset = treeview.insert_column(-1, "Name", renderer, "text" => 0)
column = treeview.get_column(col_offset - 1)
column.clickable = true
end
def setup_treeview_renderer(treeview, str)
renderer = Gtk::CellRendererText.new
col_offset = treeview.insert_column(-1, str, renderer, "text" => 0)
column = treeview.get_column(col_offset - 1)
column.clickable = true
end
def process_input(bus)
# THIS is the bad ass loop
# we should return to the glib main loop from time to time. Anyone with a
# proper way to handle it ?
bus.update_buffer
bus.messages.each do |msg|
bus.process(msg)
end
end
def start_buses
# call glibize to get dbus messages from the glib mainloop
DBus::SessionBus.instance.glibize
DBus::SystemBus.instance.glibize if ENABLE_SYSTEM
DBus::SessionBus.instance.proxy.ListNames do |_msg, names|
fill_treeview(DBus::SessionBus.instance, @sessiontreeview, names)
end
return unless ENABLE_SYSTEM
DBus::SystemBus.instance.proxy.ListNames do |_msg, names|
fill_treeview(DBus::SystemBus.instance, @systemtreeview, names)
end
end
def walk_node(model, iter, node)
node.each_pair do |key, val|
subiter = model.append(iter)
subiter[0] = key
walk_node(model, subiter, val)
end
return if node.object.nil?
node.object.interfaces.sort.each do |ifname|
subiter = model.append(iter)
subiter[0] = ifname
subiter[1] = node.object[ifname]
end
end
def introspect_services(model, bus)
el = @introspect_array.shift
if !(el =~ /^:/)
iter = model.append(nil)
iter[0] = el
puts "introspecting: #{el}"
begin
service = bus.service(el).introspect
walk_node(model, iter, service.root)
rescue Exception => e
puts "DBus Error:"
puts e.backtrace.join("\n")
end
end
!@introspect_array.empty?
end
def fill_treeview(bus, treeview, array)
model = Gtk::TreeStore.new(String, DBus::ProxyObjectInterface)
treeview.model = model
@introspect_array = array.sort
Gtk.idle_add { introspect_services(model, bus) }
end
def main
Gtk.main
end
end
DBusUI.new.main
ruby-dbus-0.13.0/examples/gdbus/launch.sh 0000755 0000041 0000041 00000000101 13004252346 020261 0 ustar www-data www-data #!/bin/sh
set -e
# for the lazy typer
ruby -w -I ../../lib gdbus
ruby-dbus-0.13.0/examples/no-introspect/ 0000755 0000041 0000041 00000000000 13004252346 020160 5 ustar www-data www-data ruby-dbus-0.13.0/examples/no-introspect/nm-test.rb 0000755 0000041 0000041 00000001075 13004252346 022102 0 ustar www-data www-data #!/usr/bin/env ruby
#
# Trivial network interface lister using NetworkManager.
# NetworkManager does not support introspection, so the api is not that sexy.
require "dbus"
bus = DBus::SystemBus.instance
nm_service = bus.service("org.freedesktop.NetworkManager")
nm_manager = nm_service.object("/org/freedesktop/NetworkManager")
poi = DBus::ProxyObjectInterface.new(nm_manager, "org.freedesktop.NetworkManager")
begin
poi.define_method("getDevices", "") # NM 0.6
p poi.getDevices
rescue Exception
poi.define_method("GetDevices", "") # NM 0.7
p poi.GetDevices
end
ruby-dbus-0.13.0/examples/no-introspect/tracker-test.rb 0000755 0000041 0000041 00000001157 13004252346 023124 0 ustar www-data www-data #!/usr/bin/env ruby
#
# Trivial network interface lister using NetworkManager.
# NetworkManager does not support introspection, so the api is not that sexy.
require "dbus"
bus = DBus::SessionBus.instance
tracker_service = bus.service("org.freedesktop.Tracker")
tracker_manager = tracker_service.object("/org/freedesktop/tracker")
poi = DBus::ProxyObjectInterface.new(tracker_manager, "org.freedesktop.Tracker.Files")
poi.define_method("GetMetadataForFilesInFolder", "in live_query_id:i, in uri:s, in fields:as, out values:aas")
p poi.GetMetadataForFilesInFolder(-1, ENV["HOME"] + "/Desktop", ["File:Name", "File:Size"])
ruby-dbus-0.13.0/examples/service/ 0000755 0000041 0000041 00000000000 13004252346 017014 5 ustar www-data www-data ruby-dbus-0.13.0/examples/service/service_newapi.rb 0000755 0000041 0000041 00000002202 13004252346 022343 0 ustar www-data www-data #!/usr/bin/env ruby
require "dbus"
require "thread"
Thread.abort_on_exception = true
class Test < DBus::Object
# Create an interface aggregating all upcoming dbus_method defines.
dbus_interface "org.ruby.SampleInterface" do
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
puts "hello(#{name}, #{name2})"
end
dbus_method :test_variant, "in stuff:v" do |variant|
p variant
end
dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
end
dbus_interface "org.ruby.AnotherInterface" do
dbus_method :ThatsALongMethodNameIThink do
puts "ThatsALongMethodNameIThink"
end
dbus_method :Reverse, "in instr:s, out outstr:s" do |instr|
outstr = instr.split(//).reverse.join
puts "got: #{instr}, replying: #{outstr}"
[outstr]
end
end
end
bus = DBus::SessionBus.instance
service = bus.request_service("org.ruby.service")
myobj = Test.new("/org/ruby/MyInstance")
service.export(myobj)
Thread.new do
i = 0
loop do
# Signal emission
myobj.SomethingJustHappened("hey", i += 1)
sleep(0.5)
end
end
puts "listening"
main = DBus::Main.new
main << bus
main.run
ruby-dbus-0.13.0/examples/service/call_service.rb 0000755 0000041 0000041 00000001045 13004252346 021777 0 ustar www-data www-data #!/usr/bin/env ruby
require "dbus"
session_bus = DBus::SessionBus.instance
ruby_srv = session_bus.service("org.ruby.service")
# Get the object from this service
player = ruby_srv.object("/org/ruby/MyInstance")
player.default_iface = "org.ruby.SampleInterface"
player.test_variant(["s", "coucou"])
player.on_signal("SomethingJustHappened") do |u, v|
puts "SomethingJustHappened: #{u} #{v}"
end
player.hello("8=======D", "(_._)")
p player["org.ruby.AnotherInterface"].Reverse("Hello world!")
main = DBus::Main.new
main << session_bus
main.run
ruby-dbus-0.13.0/examples/simple/ 0000755 0000041 0000041 00000000000 13004252346 016645 5 ustar www-data www-data ruby-dbus-0.13.0/examples/simple/get_id.rb 0000755 0000041 0000041 00000000621 13004252346 020427 0 ustar www-data www-data #! /usr/bin/env ruby
# find the library without external help
$LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
require "dbus"
bus = DBus::SystemBus.instance
driver_svc = bus["org.freedesktop.DBus"]
# p driver_svc
driver_obj = driver_svc["/"]
# p driver_obj
driver_ifc = driver_obj["org.freedesktop.DBus"]
# p driver_ifc
bus_id = driver_ifc.GetId
puts "The system bus id is #{bus_id}"
ruby-dbus-0.13.0/examples/simple/call_introspect.rb 0000755 0000041 0000041 00000001375 13004252346 022370 0 ustar www-data www-data #!/usr/bin/env ruby
require "dbus"
session_bus = DBus::SessionBus.instance
# Get the Rhythmbox service
rhythmbox = session_bus.service("org.gnome.Rhythmbox")
# Get the object from this service
player = rhythmbox.object("/org/gnome/Rhythmbox/Player")
if player.has_iface? "org.gnome.Rhythmbox.Player"
puts "We have Rhythmbox Player interface"
end
player_with_iface = player["org.gnome.Rhythmbox.Player"]
p player_with_iface.getPlayingUri
# Maybe support default_iface=(iface_str) on an ProxyObject, so
# that this is possible?
player.default_iface = "org.gnome.Rhythmbox.Player"
puts "default_iface test:"
p player.getPlayingUri
player.on_signal("elapsedChanged") do |u|
puts "elapsedChanged: #{u}"
end
main = DBus::Main.new
main << session_bus
main.run
ruby-dbus-0.13.0/examples/simple/properties.rb 0000755 0000041 0000041 00000000735 13004252346 021376 0 ustar www-data www-data #! /usr/bin/env ruby
require "dbus"
bus = DBus::SystemBus.instance
nm_service = bus["org.freedesktop.NetworkManager"]
network_manager_object = nm_service["/org/freedesktop/NetworkManager"]
nm_iface = network_manager_object["org.freedesktop.NetworkManager"]
# read a property
enabled = nm_iface["WirelessEnabled"]
if enabled
puts "Wireless is enabled"
else
puts "Wireless is disabled"
end
puts "Toggling wireless"
# write a property
nm_iface["WirelessEnabled"] = !enabled
ruby-dbus-0.13.0/examples/utils/ 0000755 0000041 0000041 00000000000 13004252346 016514 5 ustar www-data www-data ruby-dbus-0.13.0/examples/utils/listnames.rb 0000755 0000041 0000041 00000000305 13004252346 021041 0 ustar www-data www-data #!/usr/bin/env ruby
require "dbus"
d = if ARGV.member?("--system")
DBus::SystemBus.instance
else
DBus::SessionBus.instance
end
d.proxy.ListNames[0].each { |n| puts "\t#{n}" }
ruby-dbus-0.13.0/examples/utils/notify.rb 0000755 0000041 0000041 00000000535 13004252346 020357 0 ustar www-data www-data #!/usr/bin/env ruby
require "dbus"
if ARGV.size < 2
puts "Usage:"
puts "notify.rb \"title\" \"body\""
exit
end
d = DBus::SessionBus.instance
o = d["org.freedesktop.Notifications"]["/org/freedesktop/Notifications"]
i = o["org.freedesktop.Notifications"]
i.Notify("notify.rb", 0, "info", ARGV[0], ARGV[1], [], {}, 2000) do |ret, param|
end
ruby-dbus-0.13.0/doc/ 0000755 0000041 0000041 00000000000 13004252346 014303 5 ustar www-data www-data ruby-dbus-0.13.0/doc/Tutorial.md 0000644 0000041 0000041 00000041600 13004252346 016431 0 ustar www-data www-data
Welcome
=======
This is the Ruby D-Bus tutorial. It aims to show you the features of Ruby
D-Bus and as you read through the tutorial also how to use them.
© Arnaud Cornet and Paul van Tilburg; this tutorial is part of
free software; you can redistribute it and/or modify it under the
terms of the [GNU Lesser General Public License,
version 2.1](http://www.gnu.org/licenses/lgpl.html) as published by the
[Free Software Foundation](http://www.fsf.org/).
Introduction
============
This is a tutorial for Ruby D-Bus, a library to access D-Bus facilities of your
system.
What is D-Bus?
--------------
D-Bus is an RPC(Remote Procedure Call) protocol. A common setup can have
multiple D-Bus daemons running that route procedure calls and signals in
the form of messages. Each of these daemons supports a bus. A bus that
is often used by modern desktop environments, and is available per session, is
called the _session bus_. Another bus that can be available, but in a
system-wide manner, is called the _system bus_. It is used for example by
the [Hardware Abstraction Layer](http://hal.freedesktop.org/) daemon. Note
that theoretically the D-Bus RPC protocol can be used without a system or
session bus. I never came across any actual use of this though.
At the desktop level, D-Bus allows some components to interact. Typically
if you are writing an application or a personal script that wants to
interact with your web browser, your music player, or that simply wants to
pop-up a desktop notification, D-Bus comes into play.
At the system level, the Hardware Abstraction Layer is a privileged daemon
that notifies other software of hardware activities. Typically, if you
want to be notified if a CD-ROM has been loaded in, of if you want to
explore hardware, the system daemon comes into play.
The D-Bus RPC system is as we will see _object oriented_.
Buses provide access to _services_ provided in turn by running or ready to
run processes. Let me introduce some D-Bus terminology before we discuss
the API of Ruby D-Bus.
Client
------
A D-Bus client is a process that connects to a D-Bus. They issue method
calls and register to the bus for signals and events.
Service
-------
A connected client can export some of its objects and let other clients
call some of its methods. Such clients typically register a special name
like `org.freedesktop.Notifications`, the service name.
There is slightly different type of service. They are provided by
processes that can be launched by a D-Bus daemon on demand. Once they are
started by D-Bus they register a service name and behave like another
client.
Note that the buses themselves provide the `org.freedesktop.DBus` service,
and provide some features through it.
Object path
-----------
An object path is the D-Bus way to specify an object _instance_ address. A
service can provide different object instances to the outside world, so
that external processes can call methods on each of them. An object path
is an address of an instance in a very similar way that the path is an
address of a file on a file system. For example:
`/org/freedesktop/Notification` is an object path of an object provided by
the `org.freedesktop.Notification` service
**Beware**: service names and object paths can, but do _not_ have to be
related! You'll probably encounter a lot of cases though, where the
object path is a slashed version of the dotted service name.
Interface
---------
Classically in an object model, classes can implement interfaces. That is,
some method definitions grouped in an interface. This is exactly what a
D-Bus interface is as well. In D-Bus interfaces have names. These names must be
specified on method calls.
The `org.freedesktop.Notification` service provides an object instance
called `/org/freedesktop/Notification`. This instance object implements an
interface called `org.freedesktop.Notifications`. It also provides two
special D-Bus specific interfaces: `org.freedesktop.DBus.Introspect` and
`org.freedesktop.DBus.Properties`. Again, object paths, service names,
and interface names can be related but do not have to be.
Basically the `org.freedesktop.DBus.Introspect` has an `Introspect` method,
that returns XML data describing the `/org/freedesktop/Notification` object
interfaces. This is used heavily internally by Ruby D-Bus.
Method
------
A method is, well, a method in the classical meaning. It's a function that
is called in the context of an object instance. Methods have typed
parameters and return typed return values.
Signal
------
Signals are simplified method calls that do not have a return value. They
do have typed parameters though.
Message
-------
Method calls, method returns, signals, errors: all are encoded as D-Bus
messages sent over a bus. They are made of a packet header with source and
destination address, a type (method call, method reply, signal) and the
body containing the parameters (for signals and method calls) or the return
values (for a method return message).
Signature
---------
Because D-Bus is typed and dynamic, each message comes with a signature that
describes the types of the data that is contained within the message. The
signature is a string with an extremely basic language that only describes
a data type. You will need to have some knowledge of what a signature
looks like if you are setting up a service. If you are just programming a
D-Bus client, you can live without knowing about them.
Client Usage
============
This chapter discusses basic client usage
and has the following topics:
Using the library
-----------------
If you want to use the library, you have to make Ruby load it by issuing:
require 'dbus'
That's all! Now we can move on to really using it...
Connecting to a bus
-------------------
On a typical system, two buses are running, the system bus and the session
bus. The system bus can be accessed by:
bus = DBus::SystemBus.instance
Probably you already have guessed how to access the session bus. This
can be done by:
bus = DBus::SessionBus.instance
Performing method calls
-----------------------
Let me continue this example using the session bus. Let's say that I want
to access an object of some client on the session bus. This particular
D-Bus client provides a service called `org.gnome.Rhythmbox`. Let me
access this service:
rb_service = bus.service("org.gnome.Rhythmbox")
In this example I access the `org.gnome.Rhythmbox` service, which is
provided by the application
[Rhythmbox](http://www.gnome.org/projects/rhythmbox/).
OK, I have a service handle now, and I know that it exports the object
"/org/gnome/Rhythmbox/Player". I will trivially access this remote object
using:
rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
Introspection
-------------
Well, that was easy. Let's say that I know that this particular object is
introspectable. In real life most of them are. The `rb_object` object we
have here is just a handle of a remote object, in general they are called
_proxy objects_, because they are the local handle of a remote object. It
would be nice to be able to make it have methods, and that its methods send
a D-Bus call to remotely execute the actual method in another process.
Well, instating these methods for a _introspectable_ object is trivial:
rb_player.introspect
And there you go. Note that not all services or objects can be
introspected, therefore you have to do this manually! Let me remind you
that objects in D-Bus have interfaces and interfaces have methods. Let's
now access these methods:
rb_player_iface = rb_player["org.gnome.Rhythmbox.Player"]
puts rb_player_iface.getPlayingUri
As you can see, when you want to call a method on an instance object, you have
to get the correct interface. It is a bit tedious, so we have the following
shortcut that does the same thing as before:
rb_player.default_iface = "org.gnome.Rhythmbox.Player"
puts rb_player.getPlayingUri
The `default_iface=` call specifies the default interface that should be
used when non existing methods are called directly on a proxy object, and
not on one of its interfaces.
Note that the bus itself has a corresponding introspectable object. You can
access it with `bus.proxy` method. For example, you can retrieve an array of
exported service names of a bus like this:
bus.proxy.ListNames[0]
Properties
----------
Some D-Bus objects provide access to properties. They are accessed by
treating a proxy interface as a hash:
nm_iface = network_manager_object["org.freedesktop.NetworkManager"]
enabled = nm_iface["WirelessEnabled"]
puts "Wireless is " + (enabled ? "enabled":"disabled")
puts "Toggling wireless"
nm_iface["WirelessEnabled"] = ! enabled
Calling a method asynchronously
-------------------------------
D-Bus is _asynchronous_. This means that you do not have to wait for a
reply when you send a message. When you call a remote method that takes a
lot of time to process remotely, you don't want your application to hang,
right? Well the asychronousness exists for this reason. What if you dont'
want to wait for the return value of a method, but still you want to take
some action when you receive it?
There is a classical method to program this event-driven mechanism. You do
some computation, perform some method call, and at the same time you setup
a callback that will be triggered once you receive a reply. Then you run a
main loop that is responsible to call the callbacks properly. Here is how
you do it:
rb_player.getPlayingUri do |resp|
puts "The playing URI is #{resp}"
end
puts "See, I'm not waiting!"
loop = DBus::Main.new
loop << bus
loop.run
This code will print the following:
See, I'm not waiting!
The playing URI is file:///music/papapingoin.mp3
Waiting for a signal
--------------------
Signals are calls from the remote object to your program. As a client, you
set yourself up to receive a signal and handle it with a callback. Then running
the main loop triggers the callback. You can register a callback handler
as allows:
rb_player.on_signal("elapsedChanged") do |u|
puts u
end
More about introspection
------------------------
There are various ways to inspect a remote service. You can simply call
`Introspect()` and read the XML output. However, in this tutorial I assume
that you want to do it using the Ruby D-Bus API.
Notice that you can introspect a service, and not only objects:
rb_service = bus.service("org.gnome.Rhythmbox")
rb_service.introspect
p rb_service.root
This dumps a tree-like structure that represents multiple object paths. In
this particular case the output is:
{gnome => {Rhythmbox => {Player => ..fdbe625de {},Shell => ..fdbe6852e {},PlaylistManager => ..fdbe4e340 {}}>
Read this left to right: the root node is "/", it has one child node "org",
"org" has one child node "gnome", and "gnome" has one child node "Rhythmbox".
Rhythmbox has Tree child nodes "Player", "Shell" and "PlaylistManager".
These three last child nodes have a weird digit that means it has an object
instance. Such object instances are already introspected.
If the prose wasn't clear, maybe the following ASCII art will help you:
/
org
gnome
Rhythmbox
Shell (with object)
Player (with object)
PlaylistManager (with object)
### Walking the object tree
You can have an object on any node, i.e. it is not limited to leaves.
You can access a specific node like this:
rb_player = rb_service.root["org"]["gnome"]["Rhythmbox"]["Player"]
rb_player = rb_service.object("/org/gnome/Rhythmbox/Player")
The difference between the two is that for the first one, `rb_service`
needs to have been introspected. Also the obtained `rb_player` is already
introspected whereas the second `rb_player` isn't yet.
Errors
------
D-Bus calls can reply with an error instead of a return value. An error is
translated to a Ruby exception.
begin
network_manager.sleep
rescue DBus::Error => e
puts e unless e.name == "org.freedesktop.NetworkManager.AlreadyAsleepOrAwake"
end
Creating a Service
==================
This chapter deals with the opposite side of the basic client usage, namely
the creation of a D-Bus service.
Registering a service
---------------------
Now that you know how to perform D-Bus calls, and how to wait for and
handle signals, you might want to learn how to publish some object and
interface to provide them to the D-Bus world. Here is how you do that.
As you should already know, D-Bus clients that provide some object to be
called remotely are services. Here is how to allocate a name on a bus:
bus = DBus.session_bus
service = bus.request_service("org.ruby.service")
Now this client is know to the outside world as `org.ruby.service`.
Note that this is a request and it _can_ be denied! When it
is denied, an exception (`DBus::NameRequestError`) is thrown.
Exporting an object
-------------------
Now, let's define a class that we want to export:
class Test < DBus::Object
# Create an interface.
dbus_interface "org.ruby.SampleInterface" do
# Create a hello method in that interface.
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
puts "hello(#{name}, #{name2})"
end
end
end
As you can see, we define a `Test` class in which we define a
`org.ruby.SampleInterface` interface. In this interface, we define a
method. The given code block is the method's implementation. This will be
executed when remote programs performs a D-Bus call. Now the annoying part:
the actual method definition. As you can guess the call
dbus_method :hello, "in name:s, in name2:s" do ...
creates a `hello` method that takes two parameters both of type string.
The _:s_ means "of type string". Let's have a look at some other common
parameter types:
- *u* means unsigned integer
- *i* means integer
- *y* means byte
- *(ui)* means a structure having a unsigned integer and a signed one.
- *a* means array, so that "ai" means array of integers
- *as* means array of string
- *a(is)* means array of structures, each having an integer and a string.
For a full description of the available D-Bus types, please refer to the
[D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures).
Now that the class has been defined, we can instantiate an object
and export it as follows:
exported_obj = Test.new("/org/ruby/MyInstance")
service.export(exported_obj)
This piece of code above instantiates a `Test` object with a D-Bus object
path. This object is reachable from the outside world after
`service.export(exported_obj)` is called.
We also need a loop which will read and process the calls coming over the bus:
loop = DBus::Main.new
loop << bus
loop.run
### Using the exported object
Now, let's consider another program that will access our newly created service:
ruby_service = bus.service("org.ruby.service")
obj = ruby_service.object("/org/ruby/MyInstance")
obj.introspect
obj.default_iface = "org.ruby.SampleInterface"
obj.hello("giligiligiligili", "haaaaaaa")
As you can see, the object we defined earlier is automatically introspectable.
See also "Basic Client Usage".
Emitting a signal
-----------------
Let's add some example method so you can see how to return a value to the
caller and let's also define another example interface that has a signal.
class Test2 < DBus::Object
# Create an interface
dbus_interface "org.ruby.SampleInterface" do
# Create a hello method in the interface:
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
puts "hello(#{name}, #{name2})"
end
# Define a signal in the interface:
dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
end
dbus_interface "org.ruby.AnotherInterface" do
dbus_method :ThatsALongMethodNameIThink, "in name:s, out ret:s" do |name|
["So your name is #{name}"]
end
end
end
Triggering the signal is a easy as calling a method, but then this time on
a local (exported) object and not on a remote/proxy object:
exported_obj.SomethingJustHappened("blah", 1)
Note that the `ThatsALongMethodNameIThink` method is returning a single
value to the caller. Notice that you always have to return an array. If
you want to return multiple values, just have an array with multiple
values.
Replying with an error
----------------------
To reply to a dbus_method with a D-Bus error, raise a `DBus::Error`,
as constructed by the `error` convenience function:
raise DBus.error("org.example.Error.SeatOccupied"), "Seat #{seat} is occupied"
If the error name is not specified, the generic
`org.freedesktop.DBus.Error.Failed` is used.
raise DBus.error, "Seat #{seat} is occupied"
raise DBus.error
ruby-dbus-0.13.0/doc/Reference.md 0000644 0000041 0000041 00000017212 13004252346 016526 0 ustar www-data www-data Ruby D-Bus Reference
====================
This is a reference-style documentation. It's not [a tutorial for
beginners](http://dbus.freedesktop.org/doc/dbus-tutorial.html), the
reader should have knowledge of basic DBus concepts.
Client Side
-----------
This section should be enough if you only want to consume DBus APIs.
### Basic Concepts
#### Setting Up
Note that although the gem is named "ruby-dbus", the required name
is simply "dbus"
#! /usr/bin/env ruby
require "dbus"
#### Calling Methods
1. {DBus.session_bus Connect to the session bus};
2. {DBus::Connection#[] get the screensaver service}
3. {DBus::Service#[] and its screensaver object}.
4. Call one of its methods in a loop, solving [xkcd#196](http://xkcd.com/196).
mybus = DBus.session_bus
service = mybus["org.freedesktop.ScreenSaver"]
object = service["/ScreenSaver"]
loop do
object.SimulateUserActivity
sleep 5 * 60
end
##### Retrieving Return Values
A method proxy simply returns a value.
In this example SuspendAllowed returns a boolean:
mybus = DBus.session_bus
pm_s = mybus["org.freedesktop.PowerManagement"]
pm_o = pm_s["/org/freedesktop/PowerManagement"]
pm_i = pm_o["org.freedesktop.PowerManagement"]
if pm_i.CanSuspend
pm_i.Suspend
end
###### Multiple Return Values
In former versions of this library,
a method proxy always returned an array of values. This was to
accomodate the rare cases of a DBus method specifying more than one
*out* parameter. For compatibility, the behavior is preserved if you
construct a {DBus::ProxyObject} with {DBus::ApiOptions::A0},
which is what {DBus::Service#object} does.
For nearly all methods you used `Method[0]` or
`Method.first`
([I#30](https://github.com/mvidner/ruby-dbus/issues/30)).
mybus = DBus.session_bus
pm_s = mybus["org.freedesktop.PowerManagement"]
# use legacy compatibility API
pm_o = pm_s.object["/org/freedesktop/PowerManagement"]
pm_i = pm_o["org.freedesktop.PowerManagement"]
# wrong
# if pm_i.CanSuspend
# pm_i.Suspend # [false] is true!
# end
# right
if pm_i.CanSuspend[0]
pm_i.Suspend
end
#### Accessing Properties
To access properties, think of the {DBus::ProxyObjectInterface interface} as a
{DBus::ProxyObjectInterface#[] hash} keyed by strings,
or use {DBus::ProxyObjectInterface#all_properties} to get
an actual Hash of them.
sysbus = DBus.system_bus
upower_s = sysbus["org.freedesktop.UPower"]
upower_o = upower_s["/org/freedesktop/UPower"]
upower_i = upower_o["org.freedesktop.UPower"]
on_battery = upower_i["OnBattery"]
puts "Is the computer on battery now? #{on_battery}"
(TODO a writable property example)
Note that unlike for methods where the interface is inferred if unambiguous,
for properties the interface must be explicitly chosen.
That is because {DBus::ProxyObject} uses the {DBus::ProxyObject Hash#[]} API
to provide the {DBus::ProxyObjectInterface interfaces}, not the properties.
#### Asynchronous Operation
If a method call has a block attached, it is asynchronous and the block
is invoked on receiving a method_return message or an error message
##### Main Loop
For asynchronous operation an event loop is necessary. Use {DBus::Main}:
# [set up signal handlers...]
main = DBus::Main.new
main << mybus
main.run
Alternately, run the GLib main loop and add your DBus connections to it via
{DBus::Connection#glibize}.
#### Receiving Signals
To receive signals for a specific object and interface, use
{DBus::ProxyObjectInterface#on\_signal}(name, &block) or
{DBus::ProxyObject#on_signal}(name, &block), for the default interface.
sysbus = DBus.system_bus
login_s = sysbus["org.freedesktop.login1"] # part of systemd
login_o = login_s.object "/org/freedesktop/login1"
login_o.default_iface = "org.freedesktop.login1.Manager"
main = DBus::Main.new
main << sysbus
# to trigger this signal, login on the Linux console
login_o.on_signal("SessionNew") do |name, opath|
puts "New session: #{name}"
session_o = login_s.object(opath)
session_i = session_o["org.freedesktop.login1.Session"]
uid, _user_opath = session_i["User"]
puts "Its UID: #{uid}"
main.quit
end
main.run
### Intermediate Concepts
#### Names
#### Types and Values, D-Bus -> Ruby
D-Bus booleans, numbers, strings, arrays and dictionaries become their straightforward Ruby counterparts.
Structs become arrays.
Object paths become strings.
Variants are simply unpacked to become their contained type.
(ISSUE: prevents proper round-tripping!)
#### Types and Values, Ruby -> D-Bus
D-Bus has stricter typing than Ruby, so the library must decide
which D-Bus type to choose. Most of the time the choice is dictated
by the D-Bus signature.
##### Variants
If the signature expects a Variant
(which is the case for all Properties!) then an explicit mechanism is needed.
1. A pair [{DBus::Type::Type}, value] specifies to marshall *value* as
that specified type.
The pair can be produced by {DBus.variant}(signature, value) which
gives the same result as [{DBus.type}(signature), value].
ISSUE: using something else than cryptic signatures is even more painful
than remembering the signatures!
foo_i["Bar"] = DBus.variant("au", [0, 1, 1, 2, 3, 5, 8])
2. Other values are tried to fit one of these:
Boolean, Double, Array of Variants, Hash of String keyed Variants,
String, Int32, Int64.
3. **Deprecated:** A pair [String, value], where String is a valid
signature of a single complete type, marshalls value as that
type. This will hit you when you rely on method (2) but happen to have
a particular string value in an array.
##### Byte Arrays
If a byte array (`ay`) is expected you can pass a String too.
The bytes sent are according to the string's
[encoding](http://ruby-doc.org/core-2.0.0/Encoding.html).
##### nil
`nil` is not allowed by D-Bus and attempting to send it raises an exception
(but see [I#16](https://github.com/mvidner/ruby-dbus/issues/16)).
#### Errors
D-Bus calls can reply with an error instead of a return value. An error is
translated to a Ruby exception, an instance of {DBus::Error}.
nm_o = DBus.system_bus["org.freedesktop.NetworkManager"]["/org/freedesktop/NetworkManager"]
nm = nm_o["org.freedesktop.NetworkManager"]
begin
nm.Sleep(false)
rescue DBus::Error => e
puts e unless e.name == "org.freedesktop.NetworkManager.AlreadyAsleepOrAwake"
end
#### Interfaces
Methods, properties and signals of a D-Bus object always belong to one of its interfaces.
Methods can be called without specifying their interface, as long as there is no ambiguity.
There are two ways to resolve ambiguities:
1. assign an interface name to {DBus::ProxyObject#default_iface}.
2. get a specific {DBus::ProxyObjectInterface interface} of the object,
with {DBus::ProxyObject#[]} and call methods from there.
Signals and properties only work with a specific interface.
#### Thread Safety
Not there. An [incomplete attempt](https://github.com/mvidner/ruby-dbus/tree/multithreading) was made.
### Advanced Concepts
#### Bus Addresses
#### Without Introspection
#### Name Overloading
Service Side
------------
When you want to provide a DBus API.
(check that client and service side have their counterparts)
### Basic
#### Exporting a Method
##### Interfaces
##### Methods
##### Bus Names
##### Errors
#### Exporting Properties
### Advanced
#### Inheritance
#### Names
Specification Conformance
-------------------------
This section lists the known deviations from version 0.19 of
[the specification][spec].
[spec]: http://dbus.freedesktop.org/doc/dbus-specification.html
1. Properties support is basic.
ruby-dbus-0.13.0/ruby-dbus.gemspec 0000644 0000041 0000041 00000002017 13004252346 017017 0 ustar www-data www-data # -*- ruby -*-
require "rubygems"
require "rake"
GEMSPEC = Gem::Specification.new do |s|
s.name = "ruby-dbus"
# s.rubyforge_project = nil
s.summary = "Ruby module for interaction with D-Bus"
s.description = "Pure Ruby module for interaction with D-Bus IPC system"
s.version = File.read("VERSION").strip
s.license = "LGPL v2.1"
s.author = "Ruby DBus Team"
s.email = "ruby-dbus-devel@lists.luon.net"
s.homepage = "https://trac.luon.net/ruby-dbus"
s.files = FileList[
"{doc,examples,lib,spec}/**/*",
"COPYING", "NEWS.md", "Rakefile", "README.md",
"ruby-dbus.gemspec", "VERSION", ".rspec"].to_a.sort
s.require_path = "lib"
s.required_ruby_version = ">= 2.0.0"
# This is optional
# s.add_runtime_dependency "nokogiri"
s.add_development_dependency "coveralls"
s.add_development_dependency "packaging_rake_tasks"
s.add_development_dependency "rake"
s.add_development_dependency "rspec", "~> 3"
s.add_development_dependency "rubocop", "= 0.41.2"
s.add_development_dependency "simplecov"
end
ruby-dbus-0.13.0/.rspec 0000644 0000041 0000041 00000000025 13004252346 014650 0 ustar www-data www-data --color --format doc
ruby-dbus-0.13.0/spec/ 0000755 0000041 0000041 00000000000 13004252346 014470 5 ustar www-data www-data ruby-dbus-0.13.0/spec/bus_spec.rb 0000755 0000041 0000041 00000001006 13004252346 016620 0 ustar www-data www-data #!/usr/bin/env rspec
# Test the bus class
require_relative "spec_helper"
require "dbus"
describe "BusTest" do
before(:each) do
@bus = DBus::ASessionBus.new
@svc = @bus.service("org.ruby.service")
@svc.object("/").introspect
end
it "tests introspection not leaking" do
# peek inside the object to see if a cleanup step worked or not
some_hash = @bus.instance_eval { @method_call_replies || {} }
# fail: "there are leftover method handlers"
expect(some_hash.size).to eq(0)
end
end
ruby-dbus-0.13.0/spec/session_bus_spec.rb 0000755 0000041 0000041 00000005155 13004252346 020374 0 ustar www-data www-data #!/usr/bin/env rspec
require_relative "spec_helper"
require "dbus"
describe DBus::ASessionBus do
subject(:dbus_session_bus_address) { "unix:abstract=/tmp/dbus-foo,guid=123" }
describe "#session_bus_address" do
around(:each) do |example|
@original_dbus_session_bus_address = ENV["DBUS_SESSION_BUS_ADDRESS"]
example.call
ENV["DBUS_SESSION_BUS_ADDRESS"] = @original_dbus_session_bus_address
end
it "returns DBUS_SESSION_BUS_ADDRESS as it is" do
ENV["DBUS_SESSION_BUS_ADDRESS"] = dbus_session_bus_address
expect(DBus::ASessionBus.session_bus_address).to eq(dbus_session_bus_address)
end
end
describe "#address_from_file" do
let(:session_bus_file_path) { %r{\.dbus/session-bus/baz-\d} }
before do
# mocks of files for address_from_file method
machine_id_path = File.expand_path("/etc/machine-id", __FILE__)
expect(Dir).to receive(:[]).with(any_args) { [machine_id_path] }
expect(File).to receive(:read).with(machine_id_path) { "baz" }
expect(File).to receive(:exist?).with(session_bus_file_path) { true }
end
around(:each) do |example|
with_env("DISPLAY", ":0.0") do
example.call
end
end
context "when DBUS_SESSION_BUS_ADDRESS from file is surrounded by quotation marks" do
it "returns session bus address without single quotation marks" do
expect(File).to receive(:open).with(session_bus_file_path) { <<-EOS.gsub(/^\s*/, "") }
DBUS_SESSION_BUS_ADDRESS='#{dbus_session_bus_address}'
DBUS_SESSION_BUS_PID=12345
DBUS_SESSION_BUS_WINDOWID=12345678
EOS
expect(DBus::ASessionBus.address_from_file).to eq(dbus_session_bus_address)
end
it "returns session bus address without double quotation marks" do
expect(File).to receive(:open).with(session_bus_file_path) { <<-EOS.gsub(/^\s*/, "") }
DBUS_SESSION_BUS_ADDRESS="#{dbus_session_bus_address}"
DBUS_SESSION_BUS_PID=12345
DBUS_SESSION_BUS_WINDOWID=12345678
EOS
expect(DBus::ASessionBus.address_from_file).to eq(dbus_session_bus_address)
end
end
context "when DBUS_SESSION_BUS_ADDRESS from file is not surrounded by any quotation marks" do
it "returns session bus address as it is" do
expect(File).to receive(:open).with(session_bus_file_path) { <<-EOS.gsub(/^\s*/, "") }
DBUS_SESSION_BUS_ADDRESS=#{dbus_session_bus_address}
DBUS_SESSION_BUS_PID=12345
DBUS_SESSION_BUS_WINDOWID=12345678
EOS
expect(DBus::ASessionBus.address_from_file).to eq(dbus_session_bus_address)
end
end
end
end
ruby-dbus-0.13.0/spec/value_spec.rb 0000755 0000041 0000041 00000006067 13004252346 017157 0 ustar www-data www-data #!/usr/bin/env rspec
# -*- coding: utf-8 -*-
require_relative "spec_helper"
require "dbus"
describe "ValueTest" do
before(:each) do
session_bus = DBus::ASessionBus.new
@svc = session_bus.service("org.ruby.service")
@obj = @svc.object("/org/ruby/MyInstance")
@obj.default_iface = "org.ruby.SampleInterface"
end
it "tests passing an array of structs through a variant" do
triple = ["a(uuu)", []]
@obj.test_variant(triple)
quadruple = ["a(uuuu)", []] # a(uuu) works fine
# The bus disconnects us because of malformed message,
# code 12: DBUS_INVALID_TOO_MUCH_DATA
@obj.test_variant(quadruple)
end
it "tests passing an array through a variant" do
# old explicit typing
@obj.test_variant(["as", ["coucou", "kuku"]])
# automatic typing
@obj.test_variant(["coucou", "kuku"])
@obj.test_variant(["saint", "was that a word or a signature?"])
end
it "tests bouncing a variant" do
expect(@obj.bounce_variant("cuckoo")[0]).to eq("cuckoo")
expect(@obj.bounce_variant(["coucou", "kuku"])[0]).to eq(["coucou", "kuku"])
expect(@obj.bounce_variant([])[0]).to eq([])
empty_hash = {}
expect(@obj.bounce_variant(empty_hash)[0]).to eq(empty_hash)
end
it "retrieves a single return value with API V1" do
obj = @svc["/org/ruby/MyInstance"]
obj.default_iface = "org.ruby.SampleInterface"
expect(obj.bounce_variant("cuckoo")).to eq("cuckoo")
expect(obj.bounce_variant(["coucou", "kuku"])).to eq(["coucou", "kuku"])
expect(obj.bounce_variant([])).to eq([])
empty_hash = {}
expect(obj.bounce_variant(empty_hash)).to eq(empty_hash)
end
# these are ambiguous
it "tests pairs with a string" do
# deprecated
expect(@obj.bounce_variant(["s", "foo"])[0]).to eq("foo")
expect(@obj.bounce_variant(DBus.variant("s", "foo"))[0]).to eq("foo")
expect(@obj.bounce_variant([DBus.type("s"), "foo"])[0]).to eq("foo")
# does not work, because the server side forgets the explicit typing
# assert_equal ["s", "foo"], @obj.bounce_variant(["av", ["s", "foo"]])[0]
# assert_equal ["s", "foo"], @obj.bounce_variant(["as", ["s", "foo"]])[0]
# instead, use this to demonstrate that the variant is passed as expected
expect(@obj.variant_size(["s", "four"])[0]).to eq(4)
# "av" is the simplest thing that will work,
# shifting the heuristic from a pair to the individual items
expect(@obj.variant_size(["av", ["s", "four"]])[0]).to eq(2)
end
it "tests marshalling an array of variants" do
# https://trac.luon.net/ruby-dbus/ticket/30
@obj.default_iface = "org.ruby.Ticket30"
choices = []
choices << ["s", "Plan A"]
choices << ["s", "Plan B"]
# old explicit typing
expect(@obj.Sybilla(choices)[0]).to eq("Do Plan A")
# automatic typing
expect(@obj.Sybilla(["Plan A", "Plan B"])[0]).to eq("Do Plan A")
end
it "tests service returning nonarray" do
# "warning: default `to_a' will be obsolete"
@obj.the_answer
end
it "tests multibyte string" do
str = @obj.multibyte_string[0]
expect(str).to eq("あいうえお")
end
end
ruby-dbus-0.13.0/spec/server_spec.rb 0000755 0000041 0000041 00000002470 13004252346 017343 0 ustar www-data www-data #!/usr/bin/env rspec
# Test that a server survives various error cases
require_relative "spec_helper"
require "dbus"
class Foo < DBus::Object
dbus_interface "org.ruby.ServerTest" do
dbus_signal :signal_without_arguments
dbus_signal :signal_with_argument, "epsilon:d"
end
dbus_signal :signal_without_interface
rescue DBus::Object::UndefinedInterface
# raised by the preceding signal declaration
end
class Bar < DBus::Object
dbus_interface "org.ruby.ServerTest" do
# a valid Ruby symbol but an invalid DBus name; Ticket#38
dbus_signal :signal_with_a_bang!
end
rescue DBus::InvalidMethodName
# raised by the preceding signal declaration
end
describe "ServerTest" do
before(:each) do
@bus = DBus::ASessionBus.new
@svc = @bus.request_service "org.ruby.server-test"
end
after(:each) do
@bus.proxy.ReleaseName "org.ruby.server-test"
end
it "tests unexporting an object" do
obj = Foo.new "/org/ruby/Foo"
@svc.export obj
expect(@svc.unexport(obj)).to be_a DBus::Object
end
it "tests unexporting an object not exported" do
obj = Foo.new "/org/ruby/Foo"
expect(@svc.unexport(obj)).to be false
end
it "tests emiting signals" do
obj = Foo.new "/org/ruby/Foo"
@svc.export obj
obj.signal_without_arguments
obj.signal_with_argument(-0.1)
end
end
ruby-dbus-0.13.0/spec/byte_array_spec.rb 0000755 0000041 0000041 00000001746 13004252346 020203 0 ustar www-data www-data #!/usr/bin/env rspec
require_relative "spec_helper"
require "dbus"
describe "ByteArrayTest" do
before(:each) do
@bus = DBus::ASessionBus.new
@svc = @bus.service("org.ruby.service")
@obj = @svc.object("/org/ruby/MyInstance")
@obj.default_iface = "org.ruby.SampleInterface"
end
it "tests passing byte array" do
data = [0, 77, 255]
result = @obj.mirror_byte_array(data).first
expect(result).to eq(data)
end
it "tests passing byte array from string" do
data = "AAA"
result = @obj.mirror_byte_array(data).first
expect(result).to eq([65, 65, 65])
end
it "tests passing byte array from hash" do
# Hash is an Enumerable, but is caught earlier
data = { "this will" => "fail" }
expect { @obj.mirror_byte_array(data).first }.to raise_error(DBus::TypeException)
end
it "tests passing byte array from nonenumerable" do
data = Time.now
expect { @obj.mirror_byte_array(data).first }.to raise_error(DBus::TypeException)
end
end
ruby-dbus-0.13.0/spec/service_newapi.rb 0000755 0000041 0000041 00000015410 13004252346 020024 0 ustar www-data www-data #!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require_relative "spec_helper"
SimpleCov.command_name "Service Tests" if Object.const_defined? "SimpleCov"
# find the library without external help
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
require "dbus"
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties".freeze
class Test < DBus::Object
INTERFACE = "org.ruby.SampleInterface".freeze
def initialize(path)
super path
@read_me = "READ ME"
@read_or_write_me = "READ OR WRITE ME"
end
# Create an interface aggregating all upcoming dbus_method defines.
dbus_interface INTERFACE do
dbus_method :hello, "in name:s, in name2:s" do |name, name2|
puts "hello(#{name}, #{name2})"
end
dbus_method :test_variant, "in stuff:v" do |variant|
DBus.logger.debug variant.inspect
end
dbus_method :bounce_variant, "in stuff:v, out chaff:v" do |variant|
[variant]
end
dbus_method :variant_size, "in stuff:v, out size:u" do |variant|
[variant.size]
end
dbus_method :the_answer, "out answer:i" do
42
end
dbus_method :will_raise, "" do
raise "Handle this"
end
dbus_method :will_raise_error_failed, "" do
raise DBus.error, "failed as designed"
end
dbus_method :will_raise_name_error, "" do
"foo".frobnicate
end
dbus_method :Error, "in name:s, in description:s" do |name, description|
raise DBus.error(name), description
end
dbus_method :mirror_byte_array, "in bytes:ay, out mirrored:ay" do |bytes|
[bytes]
end
end
# closing and reopening the same interface
dbus_interface INTERFACE do
dbus_method :multibyte_string, "out string:s" do
"あいうえお"
end
dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
end
dbus_interface "org.ruby.AnotherInterface" do
dbus_method :ThatsALongMethodNameIThink do
puts "ThatsALongMethodNameIThink"
end
dbus_method :Reverse, "in instr:s, out outstr:s" do |instr|
outstr = instr.split(//).reverse.join
[outstr]
end
end
dbus_interface "org.ruby.Ticket30" do
dbus_method :Sybilla, "in choices:av, out advice:s" do |choices|
["Do #{choices[0]}"]
end
end
dbus_interface "org.ruby.Duplicates" do
dbus_method :the_answer, "out answer:i" do
[0]
end
dbus_method :interfaces, "out answer:i" do
raise "This DBus method is currently shadowed by ProxyObject#interfaces"
end
end
dbus_interface "org.ruby.Loop" do
# starts doing something long, but returns immediately
# and sends a signal when done
dbus_method :LongTaskBegin, "in delay:i" do |delay|
# FIXME: did not complain about mismatch between signature and block args
self.LongTaskStart
DBus.logger.debug "Long task began"
task = Thread.new do
DBus.logger.debug "Long task thread started (#{delay}s)"
sleep delay
DBus.logger.debug "Long task will signal end"
self.LongTaskEnd
end
task.abort_on_exception = true # protect from test case bugs
end
dbus_signal :LongTaskStart
dbus_signal :LongTaskEnd
end
# Properties:
# ReadMe:string, returns "READ ME" at first, then what WriteMe received
# WriteMe:string
# ReadOrWriteMe:string, returns "READ OR WRITE ME" at first
dbus_interface PROPERTY_INTERFACE do
dbus_method :Get, "in interface:s, in propname:s, out value:v" do |interface, propname|
unless interface == INTERFACE
raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
"Interface '#{interface}' not found on object '#{@path}'"
end
case propname
when "ReadMe"
[@read_me]
when "ReadOrWriteMe"
[@read_or_write_me]
when "WriteMe"
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
"Property '#{interface}.#{propname}' (on object '#{@path}') is not readable"
else
# what should happen for unknown properties
# plasma: InvalidArgs (propname), UnknownInterface (interface)
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
"Property '#{interface}.#{propname}' not found on object '#{@path}'"
end
end
dbus_method :Set, "in interface:s, in propname:s, in value:v" do |interface, propname, value|
unless interface == INTERFACE
raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
"Interface '#{interface}' not found on object '#{@path}'"
end
case propname
when "ReadMe"
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
"Property '#{interface}.#{propname}' (on object '#{@path}') is not writable"
when "ReadOrWriteMe"
@read_or_write_me = value
self.PropertiesChanged(interface, { propname => value }, [])
when "WriteMe"
@read_me = value
self.PropertiesChanged(interface, { "ReadMe" => value }, [])
else
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
"Property '#{interface}.#{propname}' not found on object '#{@path}'"
end
end
dbus_method :GetAll, "in interface:s, out value:a{sv}" do |interface|
unless interface == INTERFACE
raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
"Interface '#{interface}' not found on object '#{@path}'"
end
[
{
"ReadMe" => @read_me,
"ReadOrWriteMe" => @read_or_write_me
}
]
end
dbus_signal :PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
end
end
class Derived < Test
end
class Test2 < DBus::Object
dbus_interface "org.ruby.Test2" do
dbus_method :hi, "in name:s, out greeting:s" do |name|
"Hi, #{name}!"
end
end
end
bus = DBus::SessionBus.instance
service = bus.request_service("org.ruby.service")
myobj = Test.new("/org/ruby/MyInstance")
service.export(myobj)
derived = Derived.new "/org/ruby/MyDerivedInstance"
service.export derived
test2 = Test2.new "/org/ruby/MyInstance2"
service.export test2
# introspect every other connection, Ticket #34
# (except the one that activates us - it has already emitted
# NOC by the time we run this. Therefore the test for #34 will not work
# by running t2.rb alone, one has to run t1 before it; 'rake' does it)
mr = DBus::MatchRule.new.from_s "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
bus.add_match(mr) do |msg|
new_unique_name = msg.params[2]
unless new_unique_name.empty?
DBus.logger.debug "RRRING #{new_unique_name}"
bus.introspect_data(new_unique_name, "/") do
# ignore the result
end
end
end
puts "listening, with ruby-#{RUBY_VERSION}"
main = DBus::Main.new
main << bus
begin
main.run
rescue SystemCallError
# the test driver will kill the bus, that's OK
end
ruby-dbus-0.13.0/spec/introspection_spec.rb 0000755 0000041 0000041 00000001765 13004252346 020743 0 ustar www-data www-data #!/usr/bin/env rspec
require_relative "spec_helper"
require "dbus"
describe "IntrospectionTest" do
before(:each) do
session_bus = DBus::ASessionBus.new
svc = session_bus.service("org.ruby.service")
@obj = svc.object("/org/ruby/MyInstance")
@obj.introspect
@obj.default_iface = "org.ruby.SampleInterface"
end
it "tests wrong number of arguments" do
expect { @obj.test_variant "too", "many", "args" }.to raise_error(ArgumentError)
# not enough
expect { @obj.test_variant }.to raise_error(ArgumentError)
end
it "tests shortcut methods" do
@obj.default_iface = nil
expect(@obj.bounce_variant("varargs")).to eq(["varargs"])
# test for a duplicated method name
expect { @obj.the_answer }.to raise_error(NoMethodError)
# ensure istance methods of ProxyObject aren't overwritten by remote
# methods
expect { @obj.interfaces }.not_to raise_error
@obj.default_iface = "org.ruby.SampleInterface"
expect(@obj.the_answer).to eq([42])
end
end
ruby-dbus-0.13.0/spec/server_robustness_spec.rb 0000755 0000041 0000041 00000004166 13004252346 021636 0 ustar www-data www-data #!/usr/bin/env rspec
# Test that a server survives various error cases
require_relative "spec_helper"
require "dbus"
describe "ServerRobustnessTest" do
before(:each) do
@bus = DBus::ASessionBus.new
@svc = @bus.service("org.ruby.service")
end
# https://trac.luon.net/ruby-dbus/ticket/31
# the server should not crash
it "tests no such path with introspection" do
obj = @svc.object "/org/ruby/NotMyInstance"
expect { obj.introspect }.to raise_error(DBus::Error) do |e|
expect(e).to_not match(/timeout/)
end
end
it "tests no such path without introspection" do
obj = @svc.object "/org/ruby/NotMyInstance"
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
ifc.define_method("the_answer", "out n:i")
expect { ifc.the_answer }.to raise_error(DBus::Error) do |e|
expect(e).to_not match(/timeout/)
end
end
it "tests a method that raises" do
obj = @svc.object "/org/ruby/MyInstance"
obj.default_iface = "org.ruby.SampleInterface"
expect { obj.will_raise }.to raise_error(DBus::Error) do |e|
expect(e).to_not match(/timeout/)
end
end
it "tests a method that raises name error" do
obj = @svc.object "/org/ruby/MyInstance"
obj.default_iface = "org.ruby.SampleInterface"
expect { obj.will_raise_name_error }.to raise_error(DBus::Error) do |e|
expect(e).to_not match(/timeout/)
end
end
# https://trac.luon.net/ruby-dbus/ticket/31#comment:3
it "tests no such method without introspection" do
obj = @svc.object "/org/ruby/MyInstance"
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
ifc.define_method("not_the_answer", "out n:i")
expect { ifc.not_the_answer }.to raise_error(DBus::Error) do |e|
expect(e).to_not match(/timeout/)
end
end
it "tests no such interface without introspection" do
obj = @svc.object "/org/ruby/MyInstance"
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.NoSuchInterface")
ifc.define_method("the_answer", "out n:i")
expect { ifc.the_answer }.to raise_error(DBus::Error) do |e|
expect(e).to_not match(/timeout/)
end
end
end
ruby-dbus-0.13.0/spec/thread_safety_spec.rb 0000755 0000041 0000041 00000001343 13004252346 020655 0 ustar www-data www-data #!/usr/bin/env rspec
# Test thread safety
require_relative "spec_helper"
require "dbus"
describe "ThreadSafetyTest" do
it "tests thread competition" do
print "Thread competition: "
jobs = []
5.times do
jobs << Thread.new do
Thread.current.abort_on_exception = true
# use separate connections to avoid races
bus = DBus::ASessionBus.new
svc = bus.service("org.ruby.service")
obj = svc.object("/org/ruby/MyInstance")
obj.default_iface = "org.ruby.SampleInterface"
10.times do |i|
print "#{i} "
$stdout.flush
expect(obj.the_answer[0]).to eq(42)
sleep 0.1 * rand
end
end
end
jobs.each(&:join)
end
end
ruby-dbus-0.13.0/spec/type_spec.rb 0000755 0000041 0000041 00000000673 13004252346 017021 0 ustar www-data www-data #!/usr/bin/env rspec
require_relative "spec_helper"
require "dbus"
describe DBus do
describe ".type" do
%w{i ai a(ii) aai}.each do |s|
it "parses some type #{s}" do
expect(DBus.type(s).to_s).to be_eql s
end
end
%w{aa (ii ii) hrmp}.each do |s|
it "raises exception for invalid type #{s}" do
expect { DBus.type(s).to_s }.to raise_error DBus::Type::SignatureException
end
end
end
end
ruby-dbus-0.13.0/spec/variant_spec.rb 0000755 0000041 0000041 00000003701 13004252346 017477 0 ustar www-data www-data #!/usr/bin/env rspec
# Test marshalling variants according to ruby types
require_relative "spec_helper"
require "dbus"
describe "VariantTest" do
before(:each) do
@bus = DBus::ASessionBus.new
@svc = @bus.service("org.ruby.service")
end
def make_variant(a)
DBus::PacketMarshaller.make_variant(a)
end
it "tests make variant scalar" do
# special case: do not fail immediately, marshaller will do that
expect(make_variant(nil)).to eq(["b", nil])
expect(make_variant(true)).to eq(["b", true])
# Integers
# no byte
expect(make_variant(42)).to eq(["i", 42])
# 3_000_000_000 can be u or x.
# less specific test: just run it thru a loopback
expect(make_variant(3_000_000_000)).to eq(["x", 3_000_000_000])
expect(make_variant(5_000_000_000)).to eq(["x", 5_000_000_000])
expect(make_variant(3.14)).to eq(["d", 3.14])
expect(make_variant("foo")).to eq(["s", "foo"])
expect(make_variant(:bar)).to eq(["s", "bar"])
# left: strruct, array, dict
# object path: detect exported objects?, signature
# # by Ruby types
# class Foo
# end
# make_variant(Foo.new)
# if we don;t understand a class, the error should be informative -> new exception
end
it "tests make variant array" do
ai = [1, 2, 3]
# as = ["one", "two", "three"]
# which?
# expect(make_variant(ai)).to eq(["ai", [1, 2, 3]])
expect(make_variant(ai)).to eq(["av", [["i", 1],
["i", 2],
["i", 3]]])
a0 = []
expect(make_variant(a0)).to eq(["av", []])
end
it "tests make variant hash" do
h = { "k1" => "v1", "k2" => "v2" }
expect(make_variant(h)).to eq(["a{sv}", {
"k1" => ["s", "v1"],
"k2" => ["s", "v2"]
}])
h0 = {}
expect(make_variant(h0)).to eq(["a{sv}", {}])
end
end
ruby-dbus-0.13.0/spec/binding_spec.rb 0000755 0000041 0000041 00000004400 13004252346 017442 0 ustar www-data www-data #!/usr/bin/env rspec
# Test the binding of dbus concepts to ruby concepts
require_relative "spec_helper"
require "dbus"
describe "BindingTest" do
before(:each) do
@bus = DBus::ASessionBus.new
@svc = @bus.service("org.ruby.service")
@base = @svc.object "/org/ruby/MyInstance"
@base.default_iface = "org.ruby.SampleInterface"
end
# https://trac.luon.net/ruby-dbus/ticket/36#comment:3
it "tests class inheritance" do
derived = @svc.object "/org/ruby/MyDerivedInstance"
# it should inherit from the parent
expect(derived["org.ruby.SampleInterface"]).not_to be_nil
end
# https://trac.luon.net/ruby-dbus/ticket/36
# Interfaces and methods/signals appeared on all classes
it "tests separation of classes" do
test2 = @svc.object "/org/ruby/MyInstance2"
# it should have its own interface
expect(test2["org.ruby.Test2"]).not_to be_nil
# but not an interface of the Test class
expect(test2["org.ruby.SampleInterface"]).to be_nil
# and the parent should not get polluted by the child
expect(@base["org.ruby.Test2"]).to be_nil
end
it "tests translating errors into exceptions" do
# this is a generic call that will reply with the specified error
expect { @base.Error "org.example.Fail", "as you wish" }.to raise_error(DBus::Error) do |e|
expect(e.name).to eq("org.example.Fail")
expect(e.message).to match(/as you wish/)
end
end
it "tests generic dbus error" do
# this is a generic call that will reply with the specified error
expect { @base.will_raise_error_failed }.to raise_error(DBus::Error) do |e|
expect(e.name).to eq("org.freedesktop.DBus.Error.Failed")
expect(e.message).to match(/failed as designed/)
end
end
it "tests dynamic interface definition" do
# interfaces can be defined dynamicaly
derived = DBus::Object.new "/org/ruby/MyDerivedInstance"
# define a new interface
derived.singleton_class.instance_eval do
dbus_interface "org.ruby.DynamicInterface" do
dbus_method :hello2, "in name:s, in name2:s" do |name, name2|
puts "hello(#{name}, #{name2})"
end
end
end
# the object should have the new iface
ifaces = derived.intfs
expect(ifaces).to include "org.ruby.DynamicInterface"
end
end
ruby-dbus-0.13.0/spec/err_msg_spec.rb 0000755 0000041 0000041 00000002573 13004252346 017477 0 ustar www-data www-data #!/usr/bin/env rspec
# should report it missing on org.ruby.SampleInterface
# (on object...) instead of on DBus::Proxy::ObjectInterface
require_relative "spec_helper"
require "dbus"
describe "ErrMsgTest" do
before(:each) do
session_bus = DBus::ASessionBus.new
svc = session_bus.service("org.ruby.service")
@obj = svc.object("/org/ruby/MyInstance")
@obj.default_iface = "org.ruby.SampleInterface"
end
it "tests report dbus interface" do
# a specific exception...
# mentioning DBus and the interface
expect { @obj.NoSuchMethod }
.to raise_error(NameError, /DBus interface.*#{@obj.default_iface}/)
end
it "tests report short struct" do
expect { @obj.test_variant ["(ss)", ["too few"]] }
.to raise_error(DBus::TypeException, /1 elements but type info for 2/)
end
it "tests report long struct" do
expect { @obj.test_variant ["(ss)", ["a", "b", "too many"]] }
.to raise_error(DBus::TypeException, /3 elements but type info for 2/)
end
it "tests report nil" do
nils = [
["(s)", [nil]], # would get disconnected
["i", nil],
["a{ss}", { "foo" => nil }]
]
nils.each do |has_nil|
# TODO: want backtrace from the perspective of the caller:
# rescue/reraise in send_sync?
expect { @obj.test_variant has_nil }
.to raise_error(DBus::TypeException, /Cannot send nil/)
end
end
end
ruby-dbus-0.13.0/spec/spec_helper.rb 0000644 0000041 0000041 00000005103 13004252346 017305 0 ustar www-data www-data coverage = if ENV["COVERAGE"]
ENV["COVERAGE"] == "true"
else
# heuristics: enable for interactive builds (but not in OBS)
# or in Travis
ENV["DISPLAY"] || ENV["TRAVIS"]
end
if coverage
require "simplecov"
SimpleCov.root File.expand_path("../..", __FILE__)
# do not cover specs
SimpleCov.add_filter "_spec.rb"
# do not cover the activesupport helpers
SimpleCov.add_filter "/core_ext/"
# use coveralls for on-line code coverage reporting at Travis CI
if ENV["TRAVIS"]
require "coveralls"
end
SimpleCov.start
end
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
if Object.const_defined? "RSpec"
# http://betterspecs.org/#expect
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :expect
end
end
end
require "tempfile"
require "timeout"
TOPDIR = File.expand_path("../..", __FILE__)
# path of config file for a private bus
def config_file_path
"#{TOPDIR}/spec/tools/dbus-limited-session.conf"
end
# set ENV[variable] to value and restore it after block is done
def with_env(variable, value, &block)
old_value = ENV[variable]
ENV[variable] = value
block.call
ENV[variable] = old_value
end
# Set up a private session bus and run *block* with that.
def with_private_bus(&block)
address_file = Tempfile.new("dbus-address")
pid_file = Tempfile.new("dbus-pid")
output_file = Tempfile.new("dbus-output") # just in case
temp_dir = Dir.mktmpdir
with_env("XDG_DATA_DIRS", temp_dir) do
cmd = "dbus-daemon --nofork --config-file=#{config_file_path} " \
"--print-address=3 3>#{address_file.path} " \
"--print-pid=4 4>#{pid_file.path} " \
">#{output_file.path} 2>&1 &"
system cmd
# wait until dbus-daemon writes the info
Timeout.timeout(10) do
until File.size?(address_file) && File.size?(pid_file)
sleep 0.1
end
end
address = address_file.read.chomp
pid = pid_file.read.chomp.to_i
with_env("DBUS_SESSION_BUS_ADDRESS", address) do
block.call
end
Process.kill("TERM", pid)
end
FileUtils.rm_rf temp_dir
end
def with_service_by_activation(&block)
name = "org.ruby.service"
exec = "#{TOPDIR}/spec/service_newapi.rb"
service_dir = "#{ENV["XDG_DATA_DIRS"]}/dbus-1/services"
FileUtils.mkdir_p service_dir
# file name actually does not need to match the service name
File.open("#{service_dir}/#{name}.service", "w") do |f|
s = <