Class: Descriptor
Overview
A descriptor is a rose tree with arbitrary properties at each node, used to define GUIs declaratively.
Descriptors can be created using a DSL. For example:
ex1 = Descriptor.build(:root, :name => 'parent') do
child :name => 'foo'
child :name => 'bar'
merge_point
child :name => 'hello' do
grandchild :name => 'world'
end
end
creates a tree which has a node with no name and three children with names ‘foo’, ‘bar’, and ‘hello’, and hello having a child of its own, called ‘world’. Note that descriptor tags (:root
, :child
and :grandchild
in the example) are completely arbitrary, but they play a special role when merging, together with the :name
property.
Merging consists of taking two descriptor trees, and matching their roots by tag and name. If they match, their children are recursively matched and merged, or simply concatenated when no match is found.
For example, if ex1
above is merged with the following descriptor:
ex2 = Descriptor.build(:root, :name => 'parent') do
child :name => 'foo2'
child :name => 'hello' do
grandchild :name => 'world2'
end
end
the resulting descriptor would be equivalent to the one created by:
ex1_merged_with_ex2 = Descriptor.build(:root, :name => 'parent') do
child :name => 'foo'
child :name => 'bar'
child :name => 'foo2'
child :name => 'hello' do
grandchild :name => 'world'
grandchild :name => 'world2'
end
end
As can be seen in the example, merge points can be used to specify exactly where children of merged descriptors should be inserted.
Merge points can optionally have a count
, which specifies the number of children to be inserted on that particular point. When the count is satisfied, additional children are added at the following merge point, or, if no more merge points exist, at the bottom.
Defined Under Namespace
Classes: Builder, MergePoint
Instance Attribute Summary collapse
-
#children ⇒ Array
readonly
Children of this descriptor.
-
#opts ⇒ Hash
readonly
Properties for this descriptor.
-
#tag ⇒ Symbol
readonly
The descriptor tag.
Class Method Summary collapse
-
.build(tag, opts = { }, &blk) ⇒ Descriptor
Create a descriptor using the DSL.
Instance Method Summary collapse
-
#add_child(desc) ⇒ Object
Add a child to this descriptor.
-
#add_merge_point(position, count = -1)) ⇒ Object
Add a merge point to this descriptor.
-
#initialize(tag, opts = { }) ⇒ Descriptor
constructor
Create a descriptor with no children.
-
#merge!(other) ⇒ Boolean
Destructively merge this descriptor with another.
-
#merge_child(desc) ⇒ Object
Add a child to this descriptor, taking merge points into account.
-
#to_sexp ⇒ Object
Convert this descriptor to a human readable sexp representation.
Constructor Details
#initialize(tag, opts = { }) ⇒ Descriptor
Create a descriptor with no children.
85 86 87 88 89 |
# File 'lib/rui/descriptor.rb', line 85 def initialize(tag, opts = { }) @tag = tag @opts = opts @children = [] end |
Instance Attribute Details
#children ⇒ Array (readonly)
Returns children of this descriptor.
65 66 67 |
# File 'lib/rui/descriptor.rb', line 65 def children @children end |
#opts ⇒ Hash (readonly)
Returns properties for this descriptor.
64 65 66 |
# File 'lib/rui/descriptor.rb', line 64 def opts @opts end |
#tag ⇒ Symbol (readonly)
Returns the descriptor tag.
63 64 65 |
# File 'lib/rui/descriptor.rb', line 63 def tag @tag end |
Class Method Details
Instance Method Details
#add_child(desc) ⇒ Object
Add a child to this descriptor.
94 95 96 |
# File 'lib/rui/descriptor.rb', line 94 def add_child(desc) @children << desc end |
#add_merge_point(position, count = -1)) ⇒ Object
Add a merge point to this descriptor. Newly added merge points will not affect existing children, even if they were added with merge_child
118 119 120 121 122 123 |
# File 'lib/rui/descriptor.rb', line 118 def add_merge_point(position, count = -1) mp = MergePoint.new(position, count) @opts[:merge_points] ||= MergePoint::List.new @opts[:merge_points].add(mp) mp end |
#merge!(other) ⇒ Boolean
Destructively merge this descriptor with another.
Descriptors are merged if they match by tag and name, or if this descriptor has tag :group
and the other one has a property :group
set to the name of this descriptor.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/rui/descriptor.rb', line 143 def merge!(other) if tag == other.tag and opts[:name] == other.opts[:name] # if roots match other.children.each do |child2| # merge each of the children of the second descriptor merged = false children.each do |child| # try to match with any of the children of the first descriptor if child.merge!(child2) merged = true break end end # if no match is found, just add it as a child of the root merge_child(child2.dup) unless merged end true elsif tag == :group and other.opts[:group] == opts[:name] # if the root is the group of the second descriptor, add it as a child merge_child(other) else false end end |
#merge_child(desc) ⇒ Object
Add a child to this descriptor, taking merge points into account.
101 102 103 104 105 106 107 108 109 |
# File 'lib/rui/descriptor.rb', line 101 def merge_child(desc) mp = @opts[:merge_points].first if @opts[:merge_points] if mp @children.insert(mp.position, desc) @opts[:merge_points].step! else add_child(desc) end end |
#to_sexp ⇒ Object
Convert this descriptor to a human readable sexp representation. Descriptor properties are printed as ruby hashes.
129 130 131 |
# File 'lib/rui/descriptor.rb', line 129 def to_sexp "(#{@tag} #{@opts.inspect}#{@children.map{|c| ' ' + c.to_sexp}.join})" end |