目指そうかなRubyist RSSフィード

|

2007-04-22

[ruby]Hatena::API::Graphモジュールでおおいにはまる。  [ruby]Hatena::API::Graphモジュールでおおいにはまる。 - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [ruby]Hatena::API::Graphモジュールでおおいにはまる。 - 目指そうかなRubyist  [ruby]Hatena::API::Graphモジュールでおおいにはまる。 - 目指そうかなRubyist のブックマークコメント

graphnameが日本語だと文字化けするのです。kconvsjis,euc-jp,utf8に変換してあげて渡してあげても文字化けする。

#!/usr/bin/env ruby
require 'hatena/api/graph'
require 'kconv'

graph = Hatena::API::Graph.new('user', 'pass')
graphname = "日本語"
graph.post(graphname, Time.now, rand(10))

Hatena::API::Graphモジュールでは

:graphname => URI::encode(graphname)

して渡してるんだよなぁ。ちょっとわからんくなってきた

2007-03-28

[designpattern] Abstract Factoryパターン  [designpattern] Abstract Factoryパターン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [designpattern] Abstract Factoryパターン - 目指そうかなRubyist  [designpattern] Abstract Factoryパターン - 目指そうかなRubyist のブックマークコメント

ソース

class Item
  def initialize(caption)
    @caption = caption
  end

  def makeHTML
  end
end

class Link < Item
  def initialize(caption, url)
    super(caption)
    @url = url
  end
end

class Tray < Item
  def initialize(caption)
    super(caption)
    @tray = []
  end
  
  def add(item)
    @tray << item
  end
end

class Page
  def initialize(title, author)
    @title = title
    @author = author
    @content = []
  end

  def add(item)
    @content << item
  end

  def output
    file = @title + '.html'
    writer = File.new(file, "w")
    writer.write(self.makeHTML)
    writer.close
    puts "#{file}を作成しました"
  end

  def makeHTML
  end
end

class Factory
  def initialize
    @factory = nil
  end

  def getFactory(classname)
    @factory = eval(classname + ".new")
  end

  def createLink(caption, url)
  end

  def createTray(caption)
  end

  def createPage(title, author)
  end
end

#具体的な工場
class ListFactory
  def createLink(caption, url)
    ListLink.new(caption, url)
  end

  def createTray(caption)
    ListTray.new(caption)
  end

  def createPage(title, author)
    ListPage.new(title, author)
  end
end

#具体的なクラス
class ListLink < Link
  def initialize(caption, url)
    super(caption, url)
  end

  def makeHTML
    "  <li><a href=\"#{@url}\">#{@caption}</a></li>"
  end
end

class ListTray < Tray
  def initialize(caption)
    super(caption)
  end

  def makeHTML
    buf = []
    buf << "<li>\n"
    buf << "#{@caption}\n"
    buf << "<ul>\n"
    @tray.each {|item| buf << item.makeHTML}
    buf << "</ul>\n"
    buf << "</li>\n" 
    buf.join
  end
end

class ListPage < Page
  def initialize(title, author)
    super(title, author)
  end

  def makeHTML
    buf = []
    buf << "<html><head><title>#{@title}</title></head>\n"
    buf << "<body>\n"
    buf << "<h1>#{@title}</h1>\n"
    buf << "<ul>\n"
    @content.each {|item| buf << item.makeHTML }
    buf << "</ul>"
    buf << "<hr><address>#{@author}</address>"
    buf << "</body></html>\n"
    buf.join
  end
end

if __FILE__ == $0
  factory = Factory.new.getFactory(ARGV.shift)
  asahi = factory.createLink("朝日新聞", "http://www.asahi.com")
  yomiuri = factory.createLink("読売新聞", "http://www.yomiuri.co.jp")
  us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com")
  jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/")
  excite = factory.createLink("excite", "http://www.excite.com/")
  google = factory.createLink("google", "http://www.google.com")

  traynews = factory.createTray("新聞")
  traynews.add(yomiuri)
  traynews.add(asahi)

  trayyahoo = factory.createTray("Yahoo!")
  trayyahoo.add(us_yahoo)
  trayyahoo.add(jp_yahoo)
  
  traysearch = factory.createTray("サーチエンジン")
  traysearch.add(trayyahoo)
  traysearch.add(excite)
  traysearch.add(google)

  page = factory.createPage("LinkPage", "samurai20000")
  page.add(traynews)
  page.add(traysearch)
  page.output
end

結構頭ぐちゃぐちゃになってしまった。理解はできるんだけど頭の中でいっぱいクラスありすぎて把握できない。

[*01names.txt*][*01names.txt*]2007/04/21 14:05Great
http://mywebpage.netscape.com/adware1removal/adware-se.htm Adware Se :: http://mywebpage.netscape.com/adware1removal/adware-spyware-remover.htm Adware Spyware ::
<a href= http://mywebpage.netscape.com/adware1removal/adware-se.htm >Adware</a> ; <a href= http://mywebpage.netscape.com/adware1removal/adware-spyware-remover.htm >Adware</a> ;
[url=http://mywebpage.netscape.com/adware1removal/adware-se.htm]Adware Se[/url] .. [url=http://mywebpage.netscape.com/adware1removal/adware-spyware-remover.htm]Adware Se[/url] ..

2007-03-23

[designpattern]Builderパターン  [designpattern]Builderパターン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [designpattern]Builderパターン - 目指そうかなRubyist  [designpattern]Builderパターン - 目指そうかなRubyist のブックマークコメント

ソース

class Builder
  def makeTitle
  end

  def makeString
  end

  def makeItems
  end

  def close
  end
end

class Director
  def initialize(builder)
    @builder = builder
  end

  def construct
    @builder.makeTitle('greating')
    @builder.makeString('朝からよるにかけて')
    @builder.makeItems('おはようございます。', 'こんにちは。')
    @builder.makeString('夜に')
    @builder.makeItems('こんばんは。', 'おやすみなさい。', 'さようなら。')
    @builder.close
  end
end

class TextBuilder < Builder
  def initialize
    @buf = []
  end

  def makeTitle(title)
    @buf << "==============================================\n"
    @buf << "#{title}\n"
    @buf << "\n"
  end

  def makeString(str)
    @buf << "#{str}\n"
    @buf << "\n"
  end

  def makeItems(*items)
    items.each { |item| @buf << "- #{item}\n" }
    @buf << "\n"
  end

  def close
    @buf << "==============================================\n"
  end

  def getResult
    @buf.join
  end
end

class HTMLBuilder < Builder
  def makeTitle(title)
    @title = title
    @filename = "#{@title}.html"
    @writer = File.new(@filename, "w")
    @writer.puts("<html><head><title>#{title}</title></head><body>")
    @writer.puts("<h1>#{title}</h1>")
  end

  def makeString(str)
    @writer.puts("<p>#{str}</p>")
  end
  
  def makeItems(*items)
    @writer.puts("<ul>")
    items.each { |item| @writer.puts("<li>#{item}</li>") }
    @writer.puts("</ul>")
  end
  
  def close
    @writer.close
  end
  
  def getResult
    @filename
  end
end


if __FILE__ == $0
  textbuilder = TextBuilder.new
  director = Director.new(textbuilder)
  director.construct
  puts textbuilder.getResult
  
  htmlbuilder = HTMLBuilder.new
  director = Director.new(htmlbuilder)
  director.construct
  puts "#{htmlbuilder.getResult}が作成されました。"
end

学んだこと

上のソースではdirectorBuilderのメソッドのみを利用しているので実際に動いているのがTextかHTMLかを意識しなくて済むのがポイント

Builder
ConcreateBuilder

Builder役のインターフェースを実装。

Director

Builderインターフェースを使って実際にインスタンスを生成する

Client

Builderパターンを利用する人。

オブジェクト指向プログラミング

誰が何を知っているのかが重要

上の例では実際にどのように文章を作るかはmainは知らない。Director役によって隠蔽されている。

2007-03-22

[designpattern] Prototypeパターン  [designpattern] Prototypeパターン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [designpattern] Prototypeパターン - 目指そうかなRubyist  [designpattern] Prototypeパターン - 目指そうかなRubyist のブックマークコメント

クラスからインスタンスを生成するのではなくインスタンスコピーしてあたらしいインスタンスを生成する。

ソース

class Product
  def use(string)
  end

  def createClone
    self.dup
  end
end

class Manager
  def initialize
    @hash = {}
  end

  def register(name, product)
    @hash[name] = product
  end

  def create(name)
    p = @hash[name]
    p.createClone
  end
end

class MessageBox < Product
  def initialize(decochar)
    @decochar = decochar
  end

  def use(string)
    puts @decochar * (string.length + 4)
    puts @decochar + ' ' +  string + ' ' + @decochar
    puts @decochar * (string.length + 4)
  end
end

class UnderlinePen < Product
  def initialize(ulchar)
    @ulchar = ulchar
  end

  def use(string)
    puts "\"" + string + "\""
    puts ' ' + @ulchar * string.length
  end
end

if __FILE__ == $0 
  manager = Manager.new
  upen = UnderlinePen.new('~')
  mbox = MessageBox.new('*')
  sbox = MessageBox.new('/')
  manager.register('strong message', upen)
  manager.register('warning box', mbox)
  manager.register('slash box', sbox)
  p1 = manager.create('strong message')
  p1.use('hello world!')
  p2 = manager.create('warning box')
  p2.use('hello world!')
  p3 = manager.create('slash box')
  p3.use('hello world!')
end

学んだこと

登場人物
  • prototype
  • concreateprototype
  • client

上の例ではprototypeはProductクラス担当

congreateprototypeはMessageBoxクラスUnderlineクラス担当

なぜprototypeパターンを使うのか?
クラス名の束縛

クラス名がManagerクラスに入っていないことがポイント

クラス名と切り離して再利用可能。

上のコードなら練習問題6-1のcreateCloneメソッドを共有されてるからOK

[designpattern] Singletonパターン  [designpattern] Singletonパターン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [designpattern] Singletonパターン - 目指そうかなRubyist  [designpattern] Singletonパターン - 目指そうかなRubyist のブックマークコメント

Singletonパターン

インスタンスが一つしか存在しないことを保証するパターン

ソース

require 'test/unit'
require 'singleton'

class Test_singleton < Test::Unit::TestCase
  def test_singleton
    obj1 = MySingleton.instance
    obj2 = MySingleton.instance
    assert_equal obj1,obj2
  end

  def test_singleton_error
    assert_raise(NoMethodError){ MySingleton.new }
  end
end

class MySingleton
  include Singleton
end

学んだこと

rubyにはsingletonライブラリがすでにあることがわかった。

でも謎なのはこれいつインスタンスが生成されているのかわからないこと。

練習問題5-1

TicketMakerクラス(getNextTicketNumberメソッドを呼ぶたびに1000,1001,1002…という数をじゅんに返す)。このクラスSingletonパターンを当てはめてインスタンスが一つしか作れないようにしてください。

解答

require 'test/unit'
require 'singleton'

class Test_TicketMaker < Test::Unit::TestCase
  def test_singleton
    obj1 = TicketMaker.instance
    obj2 = TicketMaker.instance
    assert_equal obj1, obj2
  end

  def test_getNextTicketNumber
    obj1 = TicketMaker.instance
    assert_equal 1001, obj1.getNextTicketNumber
    assert_equal 1002, obj1.getNextTicketNumber
    assert_equal 1003, obj1.getNextTicketNumber
  end

  def test_singleton_error
    assert_raise(NoMethodError) { TicketMaker.new}
  end
end

class TicketMaker
  include Singleton
  def initialize
    @ticket = 1000
  end

  def getNextTicketNumber
    @ticket += 1
  end
end

2007-03-21

[designpattern] Factory Methodパターン  [designpattern] Factory Methodパターン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [designpattern] Factory Methodパターン - 目指そうかなRubyist  [designpattern] Factory Methodパターン - 目指そうかなRubyist のブックマークコメント

ソース

class Factory
  def create(owner)
    p = createProduct(owner)
    registerProduct(p)
    p
  end

  protected
  def createProduct(owner)
  end

  def registerProduct(product)
  end
end

class Product
  def use
  end
end

class IDCardFactory < Factory
  def initialize
    @owners = []
  end

  protected
  def createProduct(owner)
    IDCard.new(owner)
  end

  def registerProduct(product)
    @owners << product.owner
  end

  attr_reader :owners
end

class IDCard < Product
  def initialize(owner)
    puts "#{owner}のカードを作ります。"
    @owner = owner
  end

  def use
    puts "#{owner}のカードを使います。"
  end
  
  attr_reader :owner
end

if __FILE__ == $0
  factory = IDCardFactory.new
  card1 = factory.create("hoge")
  card2 = factory.create("foo")
  card3 = factory.create("bar")
  card1.use
  card2.use
  card3.use
end

学んだこと

Factory Methodインスタンス生成

今回のcreateProductメソッドは抽象メソッドだからサブクラスで実装することが期待される。createMethodの実装方法は以下の三通りある。

  • 抽象メソッドにする

サブクラスで実装しなかったらコンパイルエラー

サブクラスで実装されなかった場合にその実装が使われる。

サブクラスで実装しないと実行時エラー

ついでに練習問題4-2も

class Factory
  def create(owner)
    p = createProduct(owner)
    registerProduct(p)
    p
  end

  protected
  def createProduct(owner)
  end

  def registerProduct(product)
  end
end

class Product
  def use
  end
end

class IDCardFactory < Factory
  def initialize
    @owners = {}
    @count = 0
  end

  protected
  def createProduct(owner)
    @count += 1
    IDCard.new(owner, @count)
  end

  def registerProduct(product)
    @owners[product.count] =  product.owner
  end

  attr_reader :owners
end

class IDCard < Product
  def initialize(owner, count)
    puts "No.#{count} #{owner}のカードを作ります。"
    @owner = owner
    @count = count
  end

  def use
    puts "No.#{count} #{owner}のカードを使います。"
  end
  
  attr_reader :owner, :count
end

if __FILE__ == $0
  factory = IDCardFactory.new
  card1 = factory.create("hoge")
  card2 = factory.create("foo")
  card3 = factory.create("bar")
  card1.use
  card2.use
  card3.use
end
|