Module: Ruber::SettingsContainer

Included in:
AbstractProject, ConfigManager
Defined in:
lib/ruber/settings_container.rb

Overview

TODO:

Change all names referring to “option” to use the word “setting” instead

TODO:

Replace instance variables used by classes mixing-in this (for example, @dialog_class)

Module which allows including classes to store and retrieve settings and provides an interface (but not the implentation, which is a backend’s job) to write the settings to a file. It’s a part of the Ruber Settings Framework

Settings are divided into groups, and each settings has a name, so any of them can be accessed using the [group, name] pair. Each group can contain multiple settings, obviously all with different names (of course, you can have settings with the same name in different groups).

To read or write a setting, you must first add it, using the #add_setting method. This method takes what we call a settings object, that is an object describing a setting. Among other things, a setting object provides information about the name of the setting, the group it belongs to and the default value, that is the value to use for the setting if the user hasn’t changed it.

The user can change the value of the settings added to a container using the dialog returned by the #dialog method. This dialog is a sublcass of KDE::PageDialog, to which plugins can add the widgets needed to change their settings (see #add_widget). The dialog is only created when the #dialog method is called and is destroyed every time a widget is added or removed to it.

This module knows nothing about the way the data is stored to file, so it needs a backend to do the reading/writing. Refer to the ruber settings framework documentation for the interface a backend class must provide.

Notes:

  • classes mixing-in this module must call #setup_container before using the functionality it provides. Usually, this can be done from the class’s initialize method
  • the values of the options in the backend aren’t updated when they are changed using the []= method, but only when the #write method is called.
  • if you want to store a value of a custom class in a settings file, make sure you require the file the class is defined in before creating the instance of SettingsContainer associated with the configuration file (not before accessing it). This is because some backends (for example the YAML backend) create all the objects stored in it on creation

Instance variables

There are some instance variables which classes mixing-in this module may set to tune the behaviour of the module. They are:

  • @base_dir: this variable can be set to a path to use as base for settings representing a relative path. For example, if this variable is set to /home/myhome/, a setting with value /home/myhome/somefile will be stored simply as somefile
  • @dialog_class: the class to instantiate to create the dialog. It must be a subclass of SettingsDialog. If this variable isn’t set, SettingsDialog will be used.

with method calls which may be overridden

Defined Under Namespace

Classes: Proxy

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Instance Attribute Details

- (String) dialog_title (private)

The title which will be used for the dialog

Returns:

  • (String)

    the title which will be used for the dialog



438
439
440
# File 'lib/ruber/settings_container.rb', line 438

def dialog_title
  @dialog_title
end

Instance Method Details

- (SettingsContainer::Proxy) [](group) - (Object) [](group, name) - (Object) [](group, name, mode)

Returns the value of a setting been added, except in the case of one argument, where the Proxy object is always returned

Overloads:

  • - (SettingsContainer::Proxy) [](group)

    Returns a Proxy object associated with a group

    Parameters:

    • group (Symbol)

      the name of the group

    Returns:

  • - (Object) [](group, name)

    value is returned

    Parameters:

    • group (Symbol)

      the group the setting belongs to

    • name (Symbol)

      the name of the setting

    Returns:

    • (Object)

      the value of the setting. If it has never been set, the default

  • - (Object) [](group, name, mode)

    or a Pathname, it is considered as a path relative to the base directory. The absolute path, obtained by joining the base directory with the value of the setting is then returned value is returned

    Parameters:

    • group (Symbol)

      the group the setting belongs to

    • name (Symbol)

      the name of the setting

    • mode (Symbol)

      if either :abs or absolute, and if the setting is a string

    Returns:

    • (Object)

      the value of the setting. If it has never been set, the default

Raises:

  • IndexError if an option corresponding to the given group and name hasn’t



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/ruber/settings_container.rb', line 283

def [](*args)
  group, name, path_opt = args
  return Proxy.new self, group unless name
  res = @options.fetch([group, name]) do
    raise IndexError, "An option called #{name} belonging to group #{group} doesn't exist"
  end
  if @base_directory and (path_opt == :abs or path_opt == :absolute)
# The call to File.expand_path is used to avoid returning names as /base/dir/.
# if the value of the options were .
    if res.is_a? String
      res = File.expand_path(File.join(@base_directory, res))
    elsif res.is_a? Pathname
      res = (Pathname.new(@base_directory) + res).cleanpath
    end
  end
  res
end

- (Object) []=(group, name, value)

Changes the value of a setting

If the new value is a string containing an absolute path, the corresponding setting object has a relative_path method which returns true and the base directory is not nil, the string will be trasformed into a path relative to the base directory before being stored.

to the object

Parameters:

  • group (Symbol)

    the group the setting belongs to

  • name (Symbol)

    the name of the setting

  • value (Object)

    the new value of the setting

Returns:

Raises:

  • (IndexError)

    if a setting with the given name and group haven’t been added



316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/ruber/settings_container.rb', line 316

def []=(group, name, value)
  full_name = [group, name]
  opt = @known_options.fetch(full_name) do
    raise IndexError, "No option called #{name} and belonging to group #{group} exists"
  end
  if value.is_a? String and (opt.relative_path rescue false) and @base_directory
    path = Pathname.new value
    dir = Pathname.new @base_directory
    value = path.relative_path_from( dir).to_s rescue value
  end
  @options[full_name] = value
end

- (nil) add_setting(opt) Also known as: add_option

Adds a setting to the container

Note: this method also deletes the configuration dialog, so a new one will be created the next time it’s needed

following methods:

  • name: takes no arguments and returns a symbol corresponding to the name of the setting
  • group: takes no arguments and returns a symbol corresponding to the group the setting belongs to
  • default: takes one argument of class Binding and returns the default value to use for the setting

If the object also has a relative_path method and that method returns true, then the setting will be treated a a path relative to the base directory already exists

Parameters:

  • the (Object)

    settings object describing the setting to add. It must have the three

Returns:

  • (nil)

Raises:

  • ArgumentError if an option with the same name nad belonging to the same group



208
209
210
211
212
213
214
215
216
217
# File 'lib/ruber/settings_container.rb', line 208

def add_setting opt
  full_name = [opt.group, opt.name]
  if @known_options[full_name]
    raise ArgumentError, "An option with name #{opt.name} belonging to group #{opt.group} already exists"
  end
  @known_options[full_name] = opt
  @options[full_name] = @backend[opt]
  delete_dialog
  nil
end

- (nil) add_widget(w)

Instructs the container to add a widget to the associated dialog

The widget won’t be immediately added to the dialog. This method only gives the container information about the widget to insert in the dialog. The widget itself will only be created and inserted in the dialog when it will first be shown.

This method resets the dialog.

below

Parameters:

  • w (Object)

    the object describing the widget. It must have the methods documented

Options Hash (w):

  • caption (String)

    the name of the page the widget should be put into. If the page doesn’t exist in the dialog, it will be added. Otherwise, the widget will be added to the one already existing in the page

  • class_obj (Class) — default: nil

    the class of the widget to create. The class’s initialize method must take no parameters. Either this method or the code method must not be nil

  • code (String) — default: nil

    a piece of ruby code which, when executed in the TOPLEVEL_BINDING, will return the widget to add to the dialog. Either this method or the class_obje method must not be nil. If both are not nil, this method will have the precedence

  • pixmap (String) — default: ''

    the path of the pixmap to associate to the page

Returns:

  • (nil)

See Also:



383
384
385
386
387
# File 'lib/ruber/settings_container.rb', line 383

def add_widget w
  @widgets << w
  delete_dialog
  nil
end

- (Hash) collect_options (private)

The known settings and their values

and the corresponding values as values

Returns:

  • (Hash)

    a hash having the settings objects added to the container as keys



507
508
509
510
511
# File 'lib/ruber/settings_container.rb', line 507

def collect_options
  data = {}
  @known_options.each_value{|v| data[v] = @options[[v.group, v.name]]}
  data
end

- (Object) default(group, name)

The default value for a given setting

the value returned by the relative_path method of the setting object (if it exists)

Parameters:

  • group (Sybmol)

    the group the setting belongs to

  • the (String)

    name of the setting

Returns:

  • (Object)

    the default value for the setting, without taking into account

Raises:

  • IndexError if a setting with the given name and group hasn’t been added



339
340
341
342
343
344
# File 'lib/ruber/settings_container.rb', line 339

def default group, name
  opt = @known_options.fetch([group, name]) do
    raise IndexError, "No option called #{name} and belonging to group #{group} exists"
  end
  opt.default
end

- (Object) delete_dialog (private)

Deletes the dialog

After calling this method, a call to #dialog will cause a new dialog to be craeated. This is used, for example, when adding a new widget to the dialog or removing an existing one.

If the dialog hadn’t already been crated, nothing is done.



494
495
496
497
498
499
# File 'lib/ruber/settings_container.rb', line 494

def delete_dialog
  if @dialog
    @dialog.delete_later 
    @dialog = nil
  end
end

- (Qt::Dialog) dialog

The dialog associated with the container

If a dialog has already been created, it will be returned. Otherwise, another dialog will be created and filled with the widgets added to the container

The dialog will be an instance of the class stored in the @dialog_class instance variable.

Returns:

  • (Qt::Dialog)

    the dialog associated with the container.

See Also:



415
416
417
# File 'lib/ruber/settings_container.rb', line 415

def dialog
  @dialog ||= @dialog_class.new self, @known_options.values, @widgets, @dialog_title
end

- (Boolean) has_setting?(group, name) Also known as: has_option?

Whether a given setting has been added to the container

Parameters:

  • group (Symbol)

    the name the setting belongs to

  • name (Symbol)

    the name of the setting

Returns:

  • (Boolean)

    true if the setting had already been added and false otherwise



251
252
253
# File 'lib/ruber/settings_container.rb', line 251

def has_setting? group, name
  !@known_options[[group, name]].nil?
end

- (Boolean) relative_path?(group, name)

Whether a setting should be considered a relative path or not

name has a relative_path method and it returns true and false otherwise

Parameters:

  • group (Sybmol)

    the group the setting belongs to

  • the (String)

    name of the setting

Returns:

  • (Boolean)

    true if the settings object corresponding to group and



354
355
356
# File 'lib/ruber/settings_container.rb', line 354

def relative_path? group, name
  @known_options[[group, name]].relative_path.to_bool rescue false
end

- (nil) remove_setting(group, name) - (nil) remove_setting(obj) Also known as: remove_option

Removes a setting

Note: this method also deletes the configuration dialog, so a new one will be created the next time it’s needed

Overloads:

  • - (nil) remove_setting(group, name)

    Parameters:

    • group (Symbol)

      the group the setting belongs to

    • name (Symbol)

      the name of the setting to remove

    Returns:

    • (nil)
  • - (nil) remove_setting(obj)

    Parameters:

    Returns:

    • (nil)


235
236
237
238
239
240
241
242
# File 'lib/ruber/settings_container.rb', line 235

def remove_setting *args
  group, name = if args.size == 1 then [args[0].group, args[0].name]
  else args
  end
  @known_options.delete [group, name]
  @options.delete [group, name]
  delete_dialog
end

- (nil) remove_widget(w)

Removes a widget from the dialog

If the dialog doesn’t contain the widget, nothing is done. Otherwise, the dialog will be deleted

Parameters:

  • w (Qt::Widget)

    the widget to remove

Returns:

  • (nil)


398
399
400
401
# File 'lib/ruber/settings_container.rb', line 398

def remove_widget w
  deleted = @widgets.delete w
  delete_dialog if deleted
end

- (nil) setup_container(backend, base_dir = nil) (private)

Initializes instance variables needed by this module

This method must be called before any of the instance method provided by the module may be used. Usually it’s called from the constructor of the including class.

for documentation about backends to. If nil, then settings containing absolute paths will be stored as such path (that is, it doesn’t start with a /)

Parameters:

  • backend (Object)

    the backend to use. See here

  • base_dir (String, nil) (defaults to: nil)

    the directory all paths settings will be relative

Returns:

  • (nil)

Raises:

  • (ArgumentError)

    if base_dir is a string but doesn’t represent a full



455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/ruber/settings_container.rb', line 455

def setup_container backend, base_dir = nil
  @known_options = {}
  @options = {}
  @backend = backend
  @dialog = nil
  @dialog_title = nil
  @widgets = []
  @dialog_class = SettingsDialog
  if base_dir and !base_dir.match(%r{\A/})
    raise ArgumentError, "The second argument to setup_container should be either an absolute path or nil"
  end
  @base_directory = base_dir
  nil
end

- (nil) write

Writes the settings to file

If you need to modify the content of an option before writing (for example because it contains a value which can only be read if a specific plugin has been loaded), override this method and change the value of the option, then return the hash.

Returns:

  • (nil)


428
429
430
431
# File 'lib/ruber/settings_container.rb', line 428

def write
  @backend.write collect_options
  nil
end