Swiby もどき

まるごとRuby! vol.1(isbn:9784844325796) の JRuby の紹介を呼んでいて、Swiby という Swing を扱うためのライブラリを知る。その DSL になんかちょっとくすぐられたので、VisualuRuby をラップしてそれっぽいものをでっちあげて見た。


こんな感じや、

api-ordinally.rb

require 'swiby'
include Swiby

window = Frame.new
window.title = "Hello World"
window.width = 200
window.height = 100
label = Label.new
label.text = "Hello World"
window.content = label
window.visible = true

こんな感じで動く。

api-dsl.rb

require 'swiby'
include Swiby

frame do
  title "Hello World2"
  width  200
  height 100
  
  content do
    label do
      label "Hello World"
    end
  end
  
  visible true
end


ライブラリ。Frame と Label しかないとか…どんだけ貧相なんだ。

コントロールの配置はめんどくなったので VRVertLayoutManager に丸投げ。
なので見た目がそれっぽいのはコントロールがいっこのときだけ。

…。

swiby.rb

require 'vr/vruby'
require 'vr/vrcontrol'
require 'vr/vrlayout'

module Swiby
  
  def self.lazy_initializees
    @lazy_initializees ||= []
  end
  
  at_exit do
    Swiby.lazy_initializees.each{|form| form.lazy_initialize }
    VRLocalScreen.messageloop
  end
  
  #
  # Components
  #
  
  class Frame < VRForm
    
    include VRVertLayoutManager
    
    def self.new
      VRLocalScreen.newform(nil, nil, self).tap do |form|
        Swiby.lazy_initializees << form
      end
    end
    
    def lazy_initialize
      create
      show
      self.swin_visible = visible
    end
    
    def construct
      if content
        [*content].each_with_index do |control, i|
          addControl(control.as_vr_class, "control#{i}", control.caption)
        end
      end
    end
    
    attr_accessor :content
    
    alias swin_visible= visible=
    attr_accessor :visible
    
    alias title= caption=
    alias width  w
    alias height h
    
    def width=(w)
      move(x, y, w, h)
    end
    
    def height=(h)
      move(x, y, w, h)
    end
    
  end #class Frame
  
  class Label
    
    attr_accessor :text
    
    def as_vr_class
      VRStatic
    end
    
    def caption
      text
    end
    
  end #class Label
  
  #
  # DSL System
  #
  
  def frame(&block)
    Swiby::DSL::Frame.evaluate(&block).object
  end
  module_function :frame
  
  module DSL
    
    class DSLObject
      
      def self.evaluate(&block)
        new.tap do |i|
          i.instance_eval(&block)
        end
      end
      
      attr_reader :object
      
    end
    
    class Frame < DSLObject
      
      def initialize
        @object = Swiby::Frame.new
      end
      
      [:title, :width, :height, :visible].each do |name|
        define_method(name){|v| object.__send__("#{name}=", v) }
      end
      
      def content(&block)
        object.content = Content.evaluate(&block).object
      end
      
    end #class Frame
    
    class Content < DSLObject
      
      def initialize
        @object = []
      end
      
      def label(&block)
        object << Label.evaluate(&block).object
      end
      
    end #class DSLObject
    
    class Label < DSLObject
      
      def initialize
        @object = Swiby::Label.new
      end
      
      def label(str)
        object.text = str
      end
      
    end #class Label
    
  end #module DSL
  
end #module Swiby