From 0e3ef5c33ed0fa79d3fd3b61288d76079d780fc5 Mon Sep 17 00:00:00 2001
From: Paolo Capriotti
Date: Fri, 26 Jun 2009 09:55:58 +0200
Subject: [PATCH] Introduce the concept of plugin interface.
A plugin interface is a loose set of requirements a plugin must comply to.
Plugins declare the interface they implement in their initialization line.
---
lib/board/table.rb | 8 ++---
lib/factory.rb | 5 ++-
lib/games/chess/main.rb | 1 +
lib/mainwindow.rb | 2 +-
lib/plugins/celtic/celtic.rb | 3 +-
lib/plugins/clocks/digital.rb | 2 +-
lib/plugins/fantasy/fantasy.rb | 3 +-
lib/plugins/games/chess.rb | 59 +++++++++++++++++++++++++++++++++
lib/plugins/games/shogi.rb | 36 ++++++++++++++++++++
lib/plugins/layouts/cool/cool.rb | 2 +-
lib/plugins/loader.rb | 12 ++++---
lib/plugins/movelist/simple_movelist.rb | 2 +-
lib/plugins/plugin.rb | 10 +++---
lib/plugins/shogi/shogi.rb | 6 ++--
lib/plugins/squares/default.rb | 3 +-
15 files changed, 130 insertions(+), 24 deletions(-)
create mode 100644 lib/plugins/games/chess.rb
create mode 100644 lib/plugins/games/shogi.rb
diff --git a/lib/board/table.rb b/lib/board/table.rb
index 4b505af..e843ffc 100644
--- a/lib/board/table.rb
+++ b/lib/board/table.rb
@@ -26,13 +26,13 @@ class Table < Qt::GraphicsView
# load theme
@theme = Theme.new
@theme.pieces = @loader.
- get_matching((game.keywords || []) + %w(pieces)).
+ get_matching(:pieces, game.keywords || []).
new(:game => game, :shadow => true)
@theme.board = @loader.
- get_matching(%w(board), game.keywords || []).
+ get_matching(:board, game.keywords || []).
new(:game => game)
@theme.layout = @loader.
- get_matching(%w(layout), game.keywords || []).
+ get_matching(:layout, game.keywords || []).
new(game)
# recreate elements
@@ -46,7 +46,7 @@ class Table < Qt::GraphicsView
else
{}
end
- clock_class = @loader.get_matching(%w(clock))
+ clock_class = @loader.get_matching(:clock)
@elements[:clocks] = game.players.inject({}) do |res, player|
res[player] = clock_class.new(scene)
res
diff --git a/lib/factory.rb b/lib/factory.rb
index 0ffbabc..1899b36 100644
--- a/lib/factory.rb
+++ b/lib/factory.rb
@@ -1,6 +1,9 @@
class Factory
- def initialize(&blk)
+ attr_reader :component
+
+ def initialize(klass = nil, &blk)
@blk = blk
+ @component = klass
end
def new(*args)
diff --git a/lib/games/chess/main.rb b/lib/games/chess/main.rb
index e4cb490..77f0e11 100644
--- a/lib/games/chess/main.rb
+++ b/lib/games/chess/main.rb
@@ -22,6 +22,7 @@ Game.add :chess do
:validator => Validator,
:piece => Piece,
:players => [:white, :black],
+ :types => [:pawn, :knight, :bishop, :rook, :queen, :king],
:serializer => lambda {|rep|
Serializer.new(rep, validator, move, piece) },
:keywords => %w(chess),
diff --git a/lib/mainwindow.rb b/lib/mainwindow.rb
index 25803dd..3ef1963 100644
--- a/lib/mainwindow.rb
+++ b/lib/mainwindow.rb
@@ -74,7 +74,7 @@ private
@table = Table.new scene, @loader, self
@controller = Controller.new(@table)
- movelist = @loader.get_matching(%w(movelist)).new(@controller)
+ movelist = @loader.get_matching(:movelist).new(@controller)
movelist_dock = Qt::DockWidget.new(self)
movelist_dock.widget = movelist
movelist_dock.window_title = KDE.i18n("History")
diff --git a/lib/plugins/celtic/celtic.rb b/lib/plugins/celtic/celtic.rb
index 87eac1a..d663de1 100644
--- a/lib/plugins/celtic/celtic.rb
+++ b/lib/plugins/celtic/celtic.rb
@@ -4,7 +4,8 @@ require 'plugins/svg_theme'
class CelticTheme < SvgTheme
include Plugin
plugin :name => 'Celtic',
- :keywords => %w(chess pieces)
+ :interface => :pieces,
+ :keywords => %w(chess)
def initialize(opts = {})
super(opts)
diff --git a/lib/plugins/clocks/digital.rb b/lib/plugins/clocks/digital.rb
index 80b51d1..de06d96 100644
--- a/lib/plugins/clocks/digital.rb
+++ b/lib/plugins/clocks/digital.rb
@@ -9,7 +9,7 @@ class DigitalClock < Qt::GraphicsItemGroup
include Observer
plugin :name => 'Digital Clock',
- :keywords => %w(clock)
+ :interface => :clock
attr_reader :items, :rect, :clock
diff --git a/lib/plugins/fantasy/fantasy.rb b/lib/plugins/fantasy/fantasy.rb
index 72fbf2e..06fb2be 100644
--- a/lib/plugins/fantasy/fantasy.rb
+++ b/lib/plugins/fantasy/fantasy.rb
@@ -4,7 +4,8 @@ require 'plugins/svg_theme'
class FantasyTheme < SvgTheme
include Plugin
plugin :name => 'Fantasy',
- :keywords => %w(chess pieces)
+ :interface => :pieces,
+ :keywords => %w(chess)
def initialize(opts = {})
super(opts)
diff --git a/lib/plugins/games/chess.rb b/lib/plugins/games/chess.rb
new file mode 100644
index 0000000..821aacf
--- /dev/null
+++ b/lib/plugins/games/chess.rb
@@ -0,0 +1,59 @@
+require 'games/games'
+require 'games/chess/state'
+require 'games/chess/move'
+require 'games/chess/board'
+require 'games/chess/policy'
+require 'games/chess/animator'
+require 'games/chess/validator'
+require 'games/chess/serializer'
+require 'games/chess/pgn'
+require 'plugins/plugin'
+
+class ChessGame
+ include Plugin
+
+ plugin :name => 'Chess',
+ :id => :chess,
+ :interface => :game,
+ :keywords => %w(chess)
+
+ attr_reader :size, :policy, :state, :board, :move,
+ :animator, :validator, :piece, :players,
+ :types, :serializer, :game_writer,
+ :game_extensions
+
+ def initialize
+ @size = Point.new(8, 8)
+ @policy = Policy.new(Move)
+ @state_component = State
+ @state = Factory.new(State) { State.new(board.new, move, piece) }
+ @board = Factory.new(Board) { Board.new(size) }
+ @move = Move
+ @animator = Animator
+ @validator = Validator
+ @piece = Piece
+ @players = [:white, :black]
+ @types = [:pawn, :knight,:bishop, :rook, :queen, :king]
+ @serializer = lambda {|rep|
+ Serializer.new(rep, validator, move, piece) }
+ @keywords = %w(chess)
+
+ @game_writer = PGN.new(serializer.new(:compact), state)
+ @game_extensions = %w(pgn)
+ end
+
+ def game_reader
+ @game_writer
+ end
+end
+
+class Chess5x5Game < ChessGame
+ plugin :name => 'Chess 5x5',
+ :id => :chess5x5,
+ :interface => :game,
+ :keywords => %w(chess)
+
+ def initialize
+ @size = Point.new(5, 5)
+ end
+end
diff --git a/lib/plugins/games/shogi.rb b/lib/plugins/games/shogi.rb
new file mode 100644
index 0000000..97a19e3
--- /dev/null
+++ b/lib/plugins/games/shogi.rb
@@ -0,0 +1,36 @@
+require 'games/shogi/state'
+require 'games/shogi/pool'
+require 'games/shogi/move'
+require 'games/shogi/validator'
+require 'games/shogi/policy'
+require 'plugins/plugin'
+
+class ShogiGame
+ include Plugin
+
+ plugin :name => 'Shogi',
+ :id => :shogi,
+ :interface => :game,
+ :keywords => %w(shogi),
+ :depends => [:chess]
+
+ attr_reader :size, :state, :board, :pool,
+ :policy, :move, :animator, :validator,
+ :piece, :keywords, :players, :types, :actions
+
+ def initialize
+ @size = Point.new(9, 9)
+ @state = Factory.new { State.new(board.new, pool, move, piece) }
+ @board = Factory.new { deps[:chess].board.component.new size }
+ @pool = Pool
+ @piece = deps[:chess].piece
+ @move = Move
+ @validator = Validator
+ @animator = deps[:chess].animator
+ @policy = Policy.new(move, validator)
+
+ @players = [:white, :black]
+ @types = [:pawn, :lance, :horse, :silver,
+ :gold, :bishop, :rook, :king]
+ end
+end
diff --git a/lib/plugins/layouts/cool/cool.rb b/lib/plugins/layouts/cool/cool.rb
index 3c86c6c..127dbd1 100644
--- a/lib/plugins/layouts/cool/cool.rb
+++ b/lib/plugins/layouts/cool/cool.rb
@@ -4,7 +4,7 @@ class CoolLayout
include Plugin
plugin :name => 'Layouts/Cool',
- :keywords => %w(layout)
+ :interface => :layout
# values relative to unit = 1
MARGIN = 0.2
diff --git a/lib/plugins/loader.rb b/lib/plugins/loader.rb
index c78b8e5..f1babfb 100644
--- a/lib/plugins/loader.rb
+++ b/lib/plugins/loader.rb
@@ -27,11 +27,15 @@ class PluginLoader
@plugins.each_value(&blk)
end
- def get_matching(required, optional = [])
- plugins = @plugins.values.
- reject {|x| not x.matches?(required) }.
- sort_by {|x| x.score(optional) }
+ def get_matching(interface, keywords = [])
+ plugins = get_all_matching(interface).
+ sort_by {|x| x.score(keywords) }
+
raise NoPluginFound if plugins.empty?
plugins.last
end
+
+ def get_all_matching(interface)
+ @plugins.values.reject {|x| not x.implements?(interface) }
+ end
end
diff --git a/lib/plugins/movelist/simple_movelist.rb b/lib/plugins/movelist/simple_movelist.rb
index 786598a..b32a95f 100644
--- a/lib/plugins/movelist/simple_movelist.rb
+++ b/lib/plugins/movelist/simple_movelist.rb
@@ -5,7 +5,7 @@ class SimpleMoveList < Qt::ListView
include Observer
plugin :name => 'Simple Move List',
- :keywords => %w(movelist)
+ :interface => :movelist
class LinearHistoryModel < Qt::StringListModel
include Observer
diff --git a/lib/plugins/plugin.rb b/lib/plugins/plugin.rb
index 928c81b..7ff7d5a 100644
--- a/lib/plugins/plugin.rb
+++ b/lib/plugins/plugin.rb
@@ -18,14 +18,12 @@ module Plugin
@plugin_data[:name] if @plugin_data
end
- def matches?(keywords)
- keywords.all? do |k|
- @plugin_data[:keywords].include? k
- end
+ def score(keywords)
+ ((@plugin_data[:keywords] || []) & keywords).size
end
- def score(keywords)
- (@plugin_data[:keywords] & keywords).size
+ def implements?(iface)
+ @plugin_data[:interface] == iface
end
end
diff --git a/lib/plugins/shogi/shogi.rb b/lib/plugins/shogi/shogi.rb
index 7a44127..6a14430 100644
--- a/lib/plugins/shogi/shogi.rb
+++ b/lib/plugins/shogi/shogi.rb
@@ -12,7 +12,8 @@ class ShogibanBackground
BASE_DIR = File.dirname(__FILE__)
plugin :name => 'Shogiban',
- :keywords => %w(shogi board)
+ :interface => :board,
+ :keywords => %w(shogi)
def initialize(opts = {})
@squares = opts[:board_size] || opts[:game].size
@@ -64,7 +65,8 @@ class ShogiTheme
:pawn => 0.8 }
plugin :name => 'Shogi',
- :keywords => %w(shogi pieces)
+ :interface => :pieces,
+ :keywords => %w(shogi)
def initialize(opts = {})
@loader = lambda do |piece, size|
diff --git a/lib/plugins/squares/default.rb b/lib/plugins/squares/default.rb
index 6da25d9..443c8f6 100644
--- a/lib/plugins/squares/default.rb
+++ b/lib/plugins/squares/default.rb
@@ -6,7 +6,8 @@ class DefaultBackground
include Background
plugin :name => 'Default',
- :keywords => %w(chess board)
+ :interface => :board,
+ :keywords => %w(chess)
def initialize(opts)
@squares = opts[:board_size] || opts[:game].size
--
2.11.4.GIT