Skip to content

Commit

Permalink
Merge branch 'master' into cwm-tree
Browse files Browse the repository at this point in the history
  • Loading branch information
mvidner committed May 18, 2017
2 parents 9257106 + 7b26e54 commit 2983810
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 47 deletions.
30 changes: 28 additions & 2 deletions library/cwm/src/lib/cwm/abstract_widget.rb
@@ -1,6 +1,32 @@
require "abstract_method"

module CWM
# A Yast::Term that can be passed as is to Yast::UI methods
# (OpenDialog, ReplaceWidget)
#
# The normal workflow is that a {WidgetTerm} becomes a {StringTerm}
# which becomes a {UITerm}.
class UITerm < Yast::Term; end

# A Yast::Term that contains strings
# which identify the old style hash based CWM widgets.
# Can be passed to {Yast::CWMClass#ShowAndRun Yast::CWM.ShowAndRun}
#
# The normal workflow is that a {WidgetTerm} becomes a {StringTerm}
# which becomes a {UITerm}.
class StringTerm < Yast::Term; end

# A Yast::Term that contains instances of {CWM::AbstractWidget}.
# Can be passed to {Yast::CWMClass#show Yast::CWM.show}
#
# The normal workflow is that a {WidgetTerm} becomes a {StringTerm}
# which becomes a {UITerm}.
class WidgetTerm < Yast::Term; end

# A {Hash{String=>Object}} that {Yast::CWMClass} knows to handle.
# TODO: document the members
class WidgetHash < Hash; end

# Represent base for any widget used in CWM. It can be passed as "widget"
# argument. For more details about usage
# see {Yast::CWMClass#show Yast::CWM.show}
Expand All @@ -9,7 +35,7 @@ module CWM
#
# The call sequence is:
#
# - {#initialize} is called by the Ruby constructor {.new}
# - `#initialize` is called by the Ruby constructor {.new}
# - CWM#show builds a widget tree, using
# - the AbstractWidget concrete class
# - {#opt} widget options: `[:notify]` is needed if {#handle} is defined
Expand Down Expand Up @@ -106,7 +132,7 @@ def self.widget_type=(type)
# It refers to
# {#help}, {#label}, {#opt}
# {#validate}, {#init}, {#handle}, {#store}, {#cleanup}.
# @return [Hash{String => Object}]
# @return [WidgetHash]
# @raise [RuntimeError] if a required method is not implemented
# or widget_type is not set.
def cwm_definition
Expand Down
5 changes: 4 additions & 1 deletion library/cwm/src/lib/cwm/custom_widget.rb
Expand Up @@ -33,9 +33,10 @@ class CustomWidget < AbstractWidget

# @!method contents
# Must be defined by subclasses
# @return [Yast::Term] a UI term; {AbstractWidget} are not allowed inside
# @return [UITerm] a UI term; {AbstractWidget} are not allowed inside
abstract_method :contents

# @return [WidgetHash]
def cwm_definition
res = { "custom_widget" => cwm_contents }

Expand All @@ -45,6 +46,7 @@ def cwm_definition
end

# Returns all nested widgets used in contents
# @return [Array<AbstractWidget>]
def nested_widgets
Yast.import "CWM"

Expand All @@ -55,6 +57,7 @@ def nested_widgets

# return contents converted to format understandable by CWM module
# Basically it replace instance of AbstractWidget by its widget_id
# @return [StringTerm]
def cwm_contents
Yast.import "CWM"

Expand Down
76 changes: 76 additions & 0 deletions library/cwm/src/lib/cwm/rspec.rb
@@ -0,0 +1,76 @@
# in your specs:
# require "cwm/rspec"

RSpec.shared_examples "CWM::AbstractWidget" do
context "these methods are only tested if they exist" do
describe "#label" do
it "produces a String" do
next unless subject.respond_to?(:label)
expect(subject.label).to be_a String
end
end

describe "#help" do
it "produces a String" do
next unless subject.respond_to?(:help)
expect(subject.help).to be_a String
end
end

describe "#opt" do
it "produces Symbols" do
next unless subject.respond_to?(:opt)
expect(subject.opt).to be_an Enumerable
subject.opt.each do |o|
expect(o).to be_a Symbol
end
end
end

describe "#handle" do
it "produces a Symbol or nil" do
next unless subject.respond_to?(:handle)
m = subject.method(:handle)
args = m.arity == 0 ? [] : [:dummy_event]
expect(subject.handle(* args)).to be_a(Symbol).or be_nil
end
end

describe "#validate" do
it "produces a Boolean (or nil)" do
next unless subject.respond_to?(:validate)
expect(subject.validate).to be(true).or be(false).or be_nil
end
end
end
end

RSpec.shared_examples "CWM::CustomWidget" do
include_examples "CWM::AbstractWidget"
describe "#contents" do
it "produces a Term" do
expect(subject.contents).to be_a Yast::Term
end
end
end

RSpec.shared_examples "CWM::Tab" do
include_examples "CWM::CustomWidget"
end

RSpec.shared_examples "CWM::ItemsSelection" do
describe "#items" do
it "produces an array of pairs of strings" do
expect(subject.items).to be_an Enumerable
subject.items.each do |i|
expect(i[0]).to be_a String
expect(i[1]).to be_a String
end
end
end
end

RSpec.shared_examples "CWM::ComboBox" do
include_examples "CWM::AbstractWidget"
include_examples "CWM::ItemsSelection"
end
4 changes: 3 additions & 1 deletion library/cwm/src/lib/cwm/tabs.rb
Expand Up @@ -6,11 +6,12 @@ class Tab < CustomWidget
# @return [Boolean] is this the initially selected tab
attr_accessor :initial

# @return [Yast::Term] contents of the tab, can contain {AbstractWidget}s
# @return [WidgetTerm] contents of the tab, can contain {AbstractWidget}s
abstract_method :contents
# @return [String] label defines name of tab header
abstract_method :label

# @return [WidgetHash]
def cwm_definition
super.merge(
"widgets" => cwm_widgets,
Expand All @@ -20,6 +21,7 @@ def cwm_definition

# get cwm style of widget definitions
# @note internal api only used as gate to communicate with CWM
# @return [Array<WidgetHash>]
def cwm_widgets
return @cwm_widgets if @cwm_widgets

Expand Down
7 changes: 7 additions & 0 deletions library/cwm/src/lib/cwm/widget.rb
Expand Up @@ -58,6 +58,7 @@ def items
[]
end

# @return [WidgetHash]
def cwm_definition
super.merge(
"items" => items
Expand Down Expand Up @@ -249,6 +250,8 @@ class IntField < AbstractWidget

# The definition for IntField additionally supports
# `minimum` and `maximum` methods.
#
# @return [WidgetHash]
# @example minimum and maximum methods
# def minimum
# 50
Expand Down Expand Up @@ -295,6 +298,7 @@ def value=(val)
# In addition to the base definition, this honors possible
# `vspacing` and `hspacing` methods
#
# @return [WidgetHash]
# @example defining additional space between the options
# def vspacing
# 1
Expand Down Expand Up @@ -370,6 +374,7 @@ def initialize(id: "_placeholder", widget: Empty.new("_initial_placeholder"))
@widget = widget
end

# @return [UITerm]
def contents
ReplacePoint(Id(widget_id), widget_content(@widget))
end
Expand Down Expand Up @@ -421,6 +426,8 @@ def cleanup

private

# @param widget [AbstractWidget]
# @return [UITerm]
def widget_content(widget)
definition = widget.cwm_definition
definition["_cwm_key"] = widget.widget_id # a bit hacky way to pass widget id
Expand Down

0 comments on commit 2983810

Please sign in to comment.