TITLE:JRuby

概要

  • このページはJRubyで作成したSwingを使用するサンプルの一覧です。
Posted by at 2012-07-19

JRuby で Swing などのサンプル

概要

環境変数 JAVA_HOME, JRUBY_HOME を設定し、パスを通しておく。

環境変数

環境変数JAVA_HOME, JRUBY_HOMEを設定し、パスを通しておく。
> set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_04
> set JRUBY_HOME=C:\jruby-1.7.0
> set Path=%JAVA_HOME%\bin;%JRUBY_HOME%\bin;%Path%
> jruby -version
jruby 1.7.0.preview1 (ruby-1.9.3-p203) (2012-05-19 00c8c98) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_05) [Windows 7-amd64-java]
jruby 1.7.0 (1.9.3p203) 2012-10-22 ff1ebbe on Java HotSpot(TM) 64-Bit Server VM 1.7.0_09-b05 [Windows 7-amd64]

Swing + JRuby サンプル

EDT で起動(JFrameを表示)

  • Swingのコンポーネントは Event Dispatch Thread 上で扱う必要があるので、以下のサンプルでは、self が java.lang.Runnable の runメソッドを実装し、java.awt.EventQueue.invokeLater で実行している
  • require "java" より include Java が良い?
  • import より java_import javax.swing.JLabel が良い?
  • 適当なファイル名で保存して、 jruby Hoge.rb などで実行

Swing + JRuby サンプル

EDT で起動(JFrameを表示)

  • SwingのコンポーネントはEvent Dispatch Thread上で扱う必要があるので、以下のサンプルでは、selfjava.lang.Runnablerunメソッドを実装し、java.awt.EventQueue.invokeLaterで実行している
  • require "java"よりinclude Javaが良い?
  • importよりjava_import javax.swing.JLabelが良い?
  • jruby EDTSwingTest.rbと実行
#spanend
#spandel
include Java
#spanend
#spanadd
#gist(6579373)
#spanend

#spandel
java_import javax.swing.JLabel
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spandel
def create_and_show_GUI
#spanend
  frame = javax.swing.JFrame.new "Title"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add JLabel.new "Test"
  frame.set_size(320, 240)
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spandel
def run
#spanend
  create_and_show_GUI
#spandel
end
#spanend
#spandel
java.awt.EventQueue.invokeLater self
#spanend
#spandel

例外処理の記述方法(SystemLookAndFeelの設定)

  • SystemLookAndFeelを設定する際の例外処理を、begin rescueで記述する

例外処理の記述方法(SystemLookAndFeelの設定)

  • SystemLookAndFeel を設定する際の例外処理を、begin rescue で記述する
#spanend
#spandel
include Java
#spanend
#spanadd
** クラスの継承(JPanelを継承) [#extend]
#spanend
- `class MainPanel < JPanel`

#spandel
java_import javax.swing.JScrollPane
#spanend
#spandel
java_import javax.swing.JTree
#spanend
#spandel
java_import javax.swing.UIManager
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spandel
def create_and_show_GUI
#spanend
  # try{
  #   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
  # }catch(Exception e) { e.printStackTrace(); }
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = javax.swing.JFrame.new "Title"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add JScrollPane.new(JTree.new)
  frame.set_size(320, 240)
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spandel
def run
#spanend
  create_and_show_GUI
#spandel
end
#spanend
#spandel
java.awt.EventQueue.invokeLater self
#spanend
#spandel

クラスの継承(JPanelを継承)

  • class MainPanel < JPanel
#spanend
#spandel
include Java
#spanend
#spandel
java_import java.awt.Dimension
#spanend
#spandel
java_import javax.swing.JPanel
#spanend
#spandel
java_import javax.swing.JTextField
#spanend
#spandel

#spanend
#spandel
class MainPanel < JPanel
#spanend
  def initialize
    super
    field = JTextField.new 32
    self.add field
    self.preferred_size = Dimension.new(320, 240)
  end
#spandel
end
#spanend
#spandel

#spanend
#spandel
java_import javax.swing.UIManager
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spandel
def create_and_show_GUI
#spanend
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = javax.swing.JFrame.new "Title"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add MainPanel.new
  frame.pack
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spandel
def run
#spanend
  create_and_show_GUI
#spandel
end
#spanend
#spandel
java.awt.EventQueue.invokeLater self
#spanend
#spandel

無名インナークラス(JButtonにActionListenerを追加)

  • リスナーをJButtonに設定し、クリックするとJTextFieldに文字を追加

無名インナークラス(JButtonにActionListenerを追加)

#spanend
#spandel
include Java
#spanend
#spanadd
#gist(6579457)
#spanend

#spandel
java_import java.awt.Dimension
#spanend
#spandel
java_import javax.swing.JPanel
#spanend
#spandel
java_import javax.swing.JButton
#spanend
#spandel
java_import javax.swing.JTextField
#spanend
#spanadd
** インタフェースの実装(MouseListenerを追加) [#Interface]
#spanend
- `java_implements`はもう使用できない?
-- 代わりに: `class MainPanel < JPanel; include MouseListener`
-- カンマ区切りで複数指定しても可: `class MainPanel < JPanel; include MouseListener, ActionListener`
- `instanceof`
-- `self.java_kind_of?(MouseListener)`

#spandel
class MainPanel < JPanel
#spanend
  def initialize
    super
    field = JTextField.new 32
    button = JButton.new "add a"
    button.add_action_listener { |e|
      puts e
      field.text = field.text + "a"
    }
    self.add field
    self.add button
    self.preferred_size = Dimension.new(320, 240)
  end
#spandel
end
#spanend
#spanadd
#gist(6579526)
#spanend

#spandel
java_import javax.swing.UIManager
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spandel
def create_and_show_GUI
#spanend
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = javax.swing.JFrame.new "JRuby Swing JButton ActionListener"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add MainPanel.new
  frame.pack
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spandel
def run
#spanend
  create_and_show_GUI
#spandel
end
#spanend
#spandel
java.awt.EventQueue.invokeLater self
#spanend
#spandel

インタフェースの実装(MouseListenerを追加)

  • java_implements はもう使用できない?
    • 代わりに class MainPanel < JPanel; include MouseListener
    • カンマ区切りで複数指定しても可 class MainPanel < JPanel; include MouseListener, ActionListener
  • instanceof
    • self.java_kind_of?(MouseListener)
#spanend
# -*- encoding: utf-8 -*-
#spandel
include Java
#spanend
#spandel

#spanend
#spandel
java_import java.awt.event.MouseListener
#spanend
#spandel
java_import java.awt.Dimension
#spanend
#spandel
java_import javax.swing.JPanel
#spanend
#spandel
java_import javax.swing.JButton
#spanend
#spandel
java_import javax.swing.JTextField
#spanend
#spandel

#spanend
#spandel
class MainPanel < JPanel
#spanend
                include MouseListener
  def initialize
    super
    field = JTextField.new 32
    button = JButton.new "add a"
    button.add_action_listener {
      field.text = field.text + "a"
    }
#spandel

#spanend
#     # https://blogs.oracle.com/nishigaya/entry/tips_for_accessing_java_objects2
#     button.add_mouse_listener do |ev|
#       p ev
#     end
#spandel

#spanend
#     #:1 warning: singleton on non-persistent Java type #<Class:0x103bdaa8> (http://wiki.jruby.org/Persistence)
#     class << listener = java.awt.event.MouseListener.new
#       def mouseEntered(e)
#         puts "mouseEntered"
#       end
#       def mouseExited(e)
#         puts "mouseExited"
#       end
#       def mousePressed(e)
#         puts "mousePressed"
#       end
#       def mouseClicked(e)
#         puts "mouseClicked"
#       end
#       def mouseReleased(e)
#         puts "mouseReleased"
#       end
#     end
#     button.add_mouse_listener listener
#spandel

#spanend
    # puts self.java_kind_of?(MouseListener)
    button.add_mouse_listener self
#spandel

#spanend
    self.add field
    self.add button
    self.preferred_size = Dimension.new(320, 240)
  end
#spandel

#spanend
  # MouseListener
  def mouseEntered(e)
    puts "mouseEntered"
  end
  def mouseExited(e)
    puts "mouseExited"
  end
  def mousePressed(e)
    puts "mousePressed"
  end
  def mouseClicked(e)
    puts "mouseClicked"
  end
  def mouseReleased(e)
    puts "mouseReleased"
  end
#spandel
end
#spanend
#spandel

#spanend
#spandel
java_import javax.swing.UIManager
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spandel
def create_and_show_GUI
#spanend
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = javax.swing.JFrame.new "JRuby Swing JButton ActionListener"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add MainPanel.new
  frame.pack
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spandel
def run
#spanend
  create_and_show_GUI
#spandel
end
#spanend
#spandel
java.awt.EventQueue.invokeLater self
#spanend
#spandel

オーバーライドしたメソッドでsuperクラスのメソッドを呼び出すと例外が発生する

オーバーライドしたメソッドでsuperクラスのメソッドを呼び出すと例外が発生する

Exception in thread "AWT-EventQueue-0" org.jruby.exceptions.RaiseException: (NoMethodError) undefined method `paintComponent' for nil:NilClass
SuperPaint = JComponent.java_class.declared_method 'paintComponent', 'java.awt.Graphics'
などとして、関数ポインタ?を作成して実行する。
#spanend
# -*- encoding: utf-8 -*-
#spandel
include Java
#spanend
#spandel
java_import java.awt.Color
#spanend
#spandel
java_import java.awt.EventQueue
#spanend
#spandel
java_import java.awt.Font
#spanend
#spandel
java_import java.awt.RenderingHints
#spanend
#spandel
java_import java.awt.event.ActionListener
#spanend
#spandel
java_import java.awt.font.FontRenderContext
#spanend
#spandel
java_import java.awt.font.TextLayout
#spanend
#spandel
java_import javax.swing.JComponent
#spanend
#spandel
java_import javax.swing.JFrame
#spanend
#spandel
java_import javax.swing.JPanel
#spanend
#spandel
java_import javax.swing.UIManager
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spanadd
#gist(6579618)
#spanend

#spandel
class MainPanel < JPanel
#spanend
          include ActionListener
  def initialize
    super
    self.font = Font.new "serif", Font::PLAIN, 100
    @text = "JRuby Swing JPanel paintComponent Marquee Animation"
    @frc  = FontRenderContext.new nil, true, true
    @tl   = TextLayout.new @text, self.font, @frc
    @b    = @tl.bounds
    @yy   = @tl.ascent/2 + @b.y
    @xx   = 0
    javax.swing.Timer.new(10, self).start
    self.preferred_size = java.awt.Dimension.new 320, 240
  end
  SuperPaint = JComponent.java_class.declared_method 'paintComponent', 'java.awt.Graphics'
  def paintComponent(g)
    #XXX: super.paintComponent g
    SuperPaint.invoke self.java_object, g.java_object
    g.setRenderingHint RenderingHints::KEY_TEXT_ANTIALIASING,
                       RenderingHints::VALUE_TEXT_ANTIALIAS_ON
    g.setRenderingHint RenderingHints::KEY_ANTIALIASING,
                       RenderingHints::VALUE_ANTIALIAS_ON
    g.color = Color::WHITE
    g.drawLine 0, self.height/2, self.width, self.height/2
    g.color = Color::BLACK
    g.font = self.font
    g.drawString @text, self.width-@xx, self.height/2-@yy
    @xx = (self.width+@b.width-@xx > 0) ? @xx+2 : 0
  end
  def actionPerformed(e)
    self.repaint
  end
#spandel
end
#spanend
#spanadd
** 配列(JTableに行追加) [#Array]
#spanend
- `["No.", "Name", "Path"].to_java`で`ruby`の配列を`java`の配列に変換して、`JTable`の行を追加

#spandel
def create_and_show_GUI
#spanend
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = JFrame.new "JRuby Swing Marquee Animation"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add MainPanel.new
  frame.pack
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spanadd
#gist(6579639)
#spanend

#spandel
def run; create_and_show_GUI; end
#spanend
#spandel
EventQueue.invokeLater self
#spanend
#spandel

配列(JTableに行追加)

  • ["No.", "Name", "Path"].to_java でrubyの配列をjavaの配列に変換
#spanend
# -*- encoding: utf-8 -*-
#spandel
include Java
#spanend
#spandel
java_import javax.swing.UIManager
#spanend
#spandel
java_import javax.swing.WindowConstants
#spanend
#spandel
java_import javax.swing.table.DefaultTableModel
#spanend
#spandel
def make_ui
#spanend
  m = DefaultTableModel.new(nil, ["No.", "Name", "Path"].to_java)
  m.add_row java.util.Vector.new(["テスト", "あああ", "いいいい"])
  m.add_row ["aaa", "bbb", "ccc"].to_java
  t = javax.swing.JTable.new m
  p = javax.swing.JPanel.new java.awt.BorderLayout.new
  p.add javax.swing.JScrollPane.new(t)
  return p
#spandel
end
#spanend
#spandel
def run #Override
#spanend
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  f = javax.swing.JFrame.new "jruby swing"
  f.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  f.content_pane.add make_ui
  f.set_size(320, 240)
  f.location_relative_to = nil
  f.visible = true
#spandel
end
#spanend
#spandel
java.awt.EventQueue.invoke_later self
#spanend
#spandel

protected なメソッドをオーバーライドして使用

  • protected なメソッドをオーバーライドして使用できなかった
    • JRuby 1.2.0で修正?

protected なメソッドをオーバーライドして使用

  • JDK 1.6.0_18で、TableRowSorterでのソートがうまくいかなくなってい件は、JDK 1.6.0_2x で修正済
    • Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Byte cannot be cast to java.lang.Long
#spanend
# -*- encoding: utf-8 -*-
#spandel
include Java
#spanend
#spandel
java_import java.awt.BorderLayout
#spanend
#spandel
java_import java.awt.Color
#spanend
#spandel
java_import java.awt.Dimension
#spanend
#spandel
java_import java.util.Random
#spanend
#spandel
java_import java.util.Vector
#spanend
#spandel
java_import java.util.concurrent.Executors
#spanend
#spandel
java_import javax.swing.BorderFactory
#spanend
#spandel
java_import javax.swing.JButton
#spanend
#spandel
java_import javax.swing.JPanel
#spanend
#spandel
java_import javax.swing.JProgressBar
#spanend
#spandel
java_import javax.swing.JScrollPane
#spanend
#spandel
java_import javax.swing.JTable
#spanend
#spandel
java_import javax.swing.SwingWorker
#spanend
#spandel
java_import javax.swing.table.DefaultTableCellRenderer
#spanend
#spandel
java_import javax.swing.table.DefaultTableModel
#spanend
#spandel
java_import javax.swing.table.TableCellRenderer
#spanend
#spandel

#spanend
#spandel
PROGRESS_IDX = 2
#spanend
#spandel

#spanend
#spandel
class TestModel < DefaultTableModel
#spanend
  @@number  = 0
  @@columns = {
    :name=>["No.", "Name", "Progress"],
    :editable=>[false, false, false],
    :class=>[java.lang.Integer, java.lang.String, java.lang.Integer],
  }
  def add_test(test)
    self.add_row Vector.new([@@number, test.tname, test.progress])
    #self.add_row [@@number, test.tname, test.progress].to_java
    @@number = @@number+1
  end
  def getColumnCount
    return @@columns[:name].size
  end
  def getColumnName(modelIndex)
    return @@columns[:name][modelIndex]
  end
  def isCellEditable(row, col)
    return @@columns[:editable][col]
  end
  def getColumnClass(modelIndex)
    return @@columns[:class][modelIndex]
  end
#spandel
end
#spanend
#spandel

#spanend
#spandel
class Test
#spanend
  attr_accessor :tname
  attr_accessor :progress
  def initialize(tname = nil, progress = 0)
    self.tname = tname
    self.progress = java.lang.Integer.new(progress)
  end
#spandel
end
#spanend
#spandel

#spanend
#spandel
class MainPanel < JPanel
#spanend
  def initialize
    super BorderLayout.new
    model  = TestModel.new
    model.add_test Test.new("aaaa", 100)
#spandel

#spanend
    table  = JTable.new model
    table.auto_create_row_sorter = true
    table.fills_viewport_height  = true
    table.show_horizontal_lines  = false
    table.show_vertical_lines    = false
    table.intercell_spacing      = Dimension.new
    table.put_client_property "terminateEditOnFocusLost", true
#spandel

#spanend
    column = table.column_model.column 0
    column.max_width = 60
    column.min_width = 60
    column.resizable = false
#spandel

#spanend
    column = table.column_model.column PROGRESS_IDX
    bar = JProgressBar.new 0, 100
    bar.border = BorderFactory.createEmptyBorder 1,1,1,1
    renderer = table.get_default_renderer java.lang.Object
    column.set_cell_renderer do |table, obj, isSelected, hasFocus, row, column|
      text = "Done"
      if obj<0
        text = "Canceled"
      elsif obj<100
        bar.value = obj
        return bar
      end
      return renderer.getTableCellRendererComponent(
        table, text, isSelected, hasFocus, row, column)
    end
    executor = Executors.new_cached_thread_pool;
    button = JButton.new "add dummy task"
    button.add_action_listener do
      worker = ProgressWorker.new model
      #worker.addPropertyChangeListener ProgressListener.new(model)
      model.add_test Test.new("example", 0)
      worker.execute
      #executor.execute worker #JDK 1.6.0_18
    end
    self.add button, BorderLayout::SOUTH
    self.add JScrollPane.new(table)
    self.preferred_size = Dimension.new 320, 240
  end
#spandel
end
#spanend
#spandel

#spanend
#spandel
class ProgressWorker < SwingWorker
#spanend
  attr_accessor :model
  def initialize(model)
    super()
    @model = model
    @key = model.row_count
    @sleepDummy = 0.1
    @lengthOfTask = Random.new.nextInt(60) + 1
  end
  def doInBackground
    prev = 0
    current = 0
    while current<@lengthOfTask && !self.cancelled?
      current = current + 1
      begin
        sleep @sleepDummy
      rescue InterruptedException => e
        proxied_e = JavaUtilities.wrap e.cause
        proxied_e.print_stack_trace
        self.publish [-1].to_java(:Integer)
        break
      end
      #puts "#{@key}: #{i}"
      i = 100*current/@lengthOfTask
      self.publish [i].to_java :Integer
      #self.firePropertyChange("progress", prev, i)
      ##self.publish i
      prev = i
    end
    return @sleepDummy*@lengthOfTask
  end
  def process(chunks)
    chunks.each {|i|
      #@model.set_value_at i, @key, PROGRESS_IDX
      #Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException:
      # java.lang.Byte cannot be cast to java.lang.Long
      @model.set_value_at java.lang.Integer.new(i), @key, PROGRESS_IDX
    }
  end
  def done
    text = nil
    i = -1
    if self.cancelled?
      text = "Canceled"
    else
      begin
        i = self.get
        text = "Done"
      rescue Exception => e
        text = "InterruptedException"
        proxied_e = JavaUtilities.wrap e.cause
        proxied_e.print_stack_trace
      end
    end
    puts "#{@key}: #{text} : #{i}s"
  end
#spandel
end
#spanend
#spandel

#spanend
#spandel
import javax.swing.UIManager
#spanend
#spandel
import javax.swing.WindowConstants
#spanend
#spandel
def create_and_show_GUI
#spanend
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = javax.swing.JFrame.new "JRuby Swing JTable"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  frame.content_pane.add MainPanel.new
  frame.pack
  frame.location_relative_to = nil
  frame.visible = true
#spandel
end
#spanend
#spandel
def run; create_and_show_GUI; end
#spanend
#spandel
java.awt.EventQueue.invokeLater self
#spanend
#spandel

JRubyでリソース(URL)のエントリを取得してSwingで使用する

ソースコードの文字コード(エンコーディング)

  • 1.7.0以前?は、*.rbの文字コードはUTF-8固定だった?
  • 1.7.0から?は、ソースコードの先頭にマジックコメント

ソースコードの文字コード(エンコーディング)

# -*- encoding: utf-8 -*-
include Java
java_import javax.swing.UIManager
java_import javax.swing.WindowConstants
java_import javax.swing.table.DefaultTableModel
def make_ui
  p = javax.swing.JPanel.new java.awt.BorderLayout.new
  p.add javax.swing.JLabel.new("日本語")
  return p
end
def run #Override
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  f = javax.swing.JFrame.new "タイトル"
  f.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  f.content_pane.add make_ui
  f.set_size(320, 240)
  f.location_relative_to = nil
  f.visible = true
end
java.awt.EventQueue.invoke_later self

その他、JRuby + One-Liner などのサンプル

その他、JRuby + One-Liner などのサンプル

JRuby One-Liner で、UIManagerのDefaults.keySetを一覧表示する

JRuby One-Liner で、UIManagerのDefaults.keySetを一覧表示する

> jruby -rjava -e "javax.swing.UIManager.lookAndFeelDefaults.keySet.each{|o| puts o}"

One-Liner での文字コード

One-Liner での文字コード

> chcp
現在のコード ページ: 932
> jruby -J-Dfile.encoding=UTF-8 -rjava -e "puts java.net.URLEncoder.encode('日本語','UTF-8')"
> jruby -J-Dfile.encoding=UTF-8 -rjava -e 'puts java.net.URLEncoder.encode(""日本語"",""UTF-8"")'
> jruby --1.9 -U -rjava -e "puts java.net.URLEncoder.encode('日本語','UTF-8')"
> jruby -J-Dfile.encoding=UTF-8 -ruri -e "puts URI.encode('日本語')"
> jruby -ruri -e "puts URI.encode('日本語'.encode('UTF-8'))"
%E6%97%A5%E6%9C%AC%E8%AA%9E
> jruby --1.9 -rjava -e "puts java.net.URLEncoder.encode('日本語','MS932')"
> jruby --1.9 -ruri -e "puts URI.encode_www_form_component('日本語')"
> jruby -ruri -e "puts URI.encode('日本語')"
%93%FA%96%7B%8C%EA

JRuby 1.7.0.preview1 でArgumentErrorが発生する場合

  • JRuby 1.7.0.preview1 で以下のようなArgumentErrorが発生する場合、-J-Dfile.encoding=UTF-8 でOK?
    • set LANG=ja_JP.utf8 は、JRubyでは効果がない?
    • 「-J-Dfile.encoding=UTF-8」は「-E UTF-8」と同じ?

Unixtimeをiso8601形式の文字列に変換

> jruby -pe "gsub(/^[0-9]+/) {|x| Time.at(x.to_i)}" cache/recent.dat
2014-09-08 14:31:51 +0900       JRuby/PukiWiki2Markdown
...
> jruby -r time -pe "gsub(/^[0-9]+/) {|x| Time.at(x.to_i).iso8601}" cache/recent.dat
2014-09-08T14:31:51+09:00       JRuby/PukiWiki2Markdown
...

JRuby 1.7.0.preview1 でArgumentErrorが発生する場合

  • JRuby 1.7.0.preview1で以下のようなArgumentErrorが発生する場合、-J-Dfile.encoding=UTF-8を指定?
    • set LANG=ja_JP.UTF-8は、JRubyでは効果がない?
    • -J-Dfile.encoding=UTF-8-E UTF-8と同じ?
>jruby -v
jruby 1.7.0 (1.9.3p203) 2012-10-22 ff1ebbe on Java HotSpot(TM) 64-Bit Server VM
1.7.0_09-b05 [Windows 7-amd64]

>chcp
現在のコード ページ: 932

>jruby -J-Dfile.encoding=UTF-8 -ruri -e "puts URI.encode('日本語')"
%E6%97%A5%E6%9C%AC%E8%AA%9E

>jruby -E UTF-8 -ruri -e "puts URI.encode('日本語')"
%93%FA%96%7B%8C%EA
  • JRuby 1.7.0.preview2 では、「-E UTF-8」の方が良さそう
  • JRuby 1.7.0.preview2では、-E UTF-8の方が良さそう
lines = src.rstrip.split(/\r?\n/).map {|line| line.chomp }
C:\pukiwiki2markdown>jruby p2m.rb wiki
ArgumentError: invalid byte sequence in Windows-31J
   split at org/jruby/RubyString.java:4643
 to_html at p2m.rb:45
    main at p2m.rb:219
    each at org/jruby/RubyArray.java:1611
    main at p2m.rb:214
  (root) at p2m.rb:234
C:\pukiwiki2markdown>jruby -J-Dfile.encoding=UTF-8 p2m.rb wiki
wiki/2010-04-12-swing-leaftreecelleditor.markdown
wiki/2007-06-18-swing-leftclippedcombobox.markdown
...
C:\pukiwiki2markdown>jruby -E UTF-8 p2m.rb wiki
wiki/2011-07-18-swing-listmouseselection.markdown
...

JRuby で PukiWiki のファイル名をデコード

JRuby で PukiWiki のファイル名をデコード

if ARGV[0] == nil then
  while line = STDIN.gets
    STDOUT.puts "#{line.gsub!(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')} }"
  end
else
  Dir::glob("*.#{ARGV[0]}").each {|f|
    puts "#{f.gsub!(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')} }"
  }
end
> ls *.txt | jruby decode.rb
> ls *.txt | jruby -pe "$_.gsub!(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')}"

PukiWiki形式のテキストをMarkdown形式のファイルに変換する

JRuby で PukiWiki のファイル名にエンコード

> jruby -pe 'gsub(/^([0-9]+)\t(.+)$/){[$1,$2.gsub(/./){|x|x.ord.to_s(16).upcase}].join("\t")}' cache/recent.dat

PukiWiki形式のテキストをMarkdown形式のファイルに変換する

PukiWiki形式のテキストをMarkdown形式のファイルに変換するに移動

リンク

PukiWikiのbackupファイルから、公開日時を取得する

  • PukiWikibackupフォルダ以下にある.gzファイルから、そのファイルの公開日時を取得する
    • 一行目からUnixtimeを取得しているだけなので、履歴が$maxageを超えている場合は不正確になる
#spanend
#spanadd
#!/usr/bin/env ruby
#spanend
#spanadd
require 'fileutils'
#spanend
#spanadd
require 'zlib'
#spanend
#spanadd
require 'time'
#spanend
#spanadd

#spanend
#spanadd
#h = Hash.new
#spanend
#spanadd
path = "/tmp/pukiwiki/backup"
#spanend
#spanadd
Dir::foreach(path) do |f|
#spanend
  next if f == "." or f == ".." or !f.end_with?(".gz")
  ap = "#{path}/#{f}"
  Zlib::GzipReader.open(ap) do |gz|
    n = f.sub(/\.gz$/, "").gsub(/[A-F\d]{2}/){|x|[x.hex].pack('C*')}
    t = gz.gets.sub(/^[>]+ ?[0-9]* /, "") #一行目から日時を取得
    x = Time.at(t.to_i).iso8601
    puts "#{n}\t#{x}"
    #h.store(n, x)
    gz.close
  end
#spanadd
end
#spanend
#spanadd

参考リンク

コメント

コメント