| 1 | #!/usr/bin/env ruby |
|---|
| 2 | |
|---|
| 3 | require "rubygems" |
|---|
| 4 | require "hparser" |
|---|
| 5 | require "pp" |
|---|
| 6 | |
|---|
| 7 | parsed = HParser::Parser.new.parse(File.read(__FILE__)[/__END__\n([\s\S]+)/, 1]) |
|---|
| 8 | |
|---|
| 9 | sections = parsed.inject([[]]) do |r,element| |
|---|
| 10 | element.instance_variable_set(:@level, element.level + 1) if element.kind_of?(HParser::Block::Head) |
|---|
| 11 | if element.kind_of?(HParser::Block::Head) && element.level == 2 |
|---|
| 12 | r << [element] |
|---|
| 13 | else |
|---|
| 14 | r.last << element |
|---|
| 15 | end |
|---|
| 16 | r |
|---|
| 17 | end |
|---|
| 18 | |
|---|
| 19 | require "erb" |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | ERB.new(<<'EOS', $SAFE, "<>").run(binding) |
|---|
| 23 | <% if ENV['REQUEST_METHOD'] %> |
|---|
| 24 | Content-Type: text/html |
|---|
| 25 | |
|---|
| 26 | <% end %> |
|---|
| 27 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
|---|
| 28 | <html xmlns="http://www.w3.org/1999/xhtml"> |
|---|
| 29 | <head> |
|---|
| 30 | <title></title> |
|---|
| 31 | |
|---|
| 32 | <link rel="stylesheet" type="text/css" href="lt.css" media="screen,tv"/> |
|---|
| 33 | <meta name="robots" content="noindex,nofollow"/> |
|---|
| 34 | |
|---|
| 35 | <script type="text/javascript" src="lib/jquery-1.2.6.min.js"></script> |
|---|
| 36 | <script type="text/javascript" src="lib/jquery.blockUI.js"></script> |
|---|
| 37 | <script type="text/javascript" src="lib/keystring.js"></script> |
|---|
| 38 | <script type="text/javascript" src="lib/lt.js"></script> |
|---|
| 39 | </head> |
|---|
| 40 | <body> |
|---|
| 41 | <div id="whole"> |
|---|
| 42 | <h1 id="top"><a href="/"></a></h1> |
|---|
| 43 | |
|---|
| 44 | <div id="content"> |
|---|
| 45 | <% sections.each do |elements| next if elements.all? {|i| i.kind_of? HParser::Block::Empty } %> |
|---|
| 46 | <div class="section"> |
|---|
| 47 | <%= elements.map {|i| i.to_html }.join("\n") %> |
|---|
| 48 | </div> |
|---|
| 49 | |
|---|
| 50 | <% end %> |
|---|
| 51 | </div> |
|---|
| 52 | |
|---|
| 53 | <div id="footer"> |
|---|
| 54 | <address>© 2008 cho45@lowreal.net</address> |
|---|
| 55 | </div> |
|---|
| 56 | </div> |
|---|
| 57 | </body> |
|---|
| 58 | </html> |
|---|
| 59 | EOS |
|---|
| 60 | |
|---|
| 61 | __END__ |
|---|
| 62 | |
|---|
| 63 | * net-irc |
|---|
| 64 | |
|---|
| 65 | - cho45 |
|---|
| 66 | - http://www.lowreal.net/ |
|---|
| 67 | - google 「ちんこ演算子の人」 |
|---|
| 68 | -- Chemr (きめぇwww) |
|---|
| 69 | -- JSDeferred |
|---|
| 70 | -- $X |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | * Agenda |
|---|
| 74 | |
|---|
| 75 | + Introducing to net-irc |
|---|
| 76 | + Applications using net-irc |
|---|
| 77 | + Citrus IRC BOT framework |
|---|
| 78 | + About the DSL (or something DSL-ish) |
|---|
| 79 | + DSL in the language |
|---|
| 80 | |
|---|
| 81 | ><!-- |
|---|
| 82 | comment |
|---|
| 83 | -->< |
|---|
| 84 | |
|---|
| 85 | |
|---|
| 86 | * |
|---|
| 87 | ><div class="title-leaf">< |
|---|
| 88 | Introducing to net-irc |
|---|
| 89 | ></div>< |
|---|
| 90 | |
|---|
| 91 | * My IRC status |
|---|
| 92 | |
|---|
| 93 | - irssi user |
|---|
| 94 | - window number -> 54 (not channel num) |
|---|
| 95 | - IRC addict |
|---|
| 96 | |
|---|
| 97 | * ... |
|---|
| 98 | |
|---|
| 99 | I want to watch all information by IRC. |
|---|
| 100 | |
|---|
| 101 | - twitter... |
|---|
| 102 | - lingr... |
|---|
| 103 | - server log... |
|---|
| 104 | |
|---|
| 105 | * ... |
|---|
| 106 | |
|---|
| 107 | - Posting to mixi... |
|---|
| 108 | - Recent hatena stars... |
|---|
| 109 | - Posting to Hatena Haiku... |
|---|
| 110 | - etc.. etc.. |
|---|
| 111 | |
|---|
| 112 | * ... |
|---|
| 113 | |
|---|
| 114 | But there were no library to write IRC server easily... |
|---|
| 115 | |
|---|
| 116 | And I made it. |
|---|
| 117 | |
|---|
| 118 | |
|---|
| 119 | * What is net-irc? |
|---|
| 120 | |
|---|
| 121 | - http://lowreal.rubyforge.org/net-irc/ |
|---|
| 122 | |
|---|
| 123 | - Is IRC library |
|---|
| 124 | - Parser from RICE by akira yamada |
|---|
| 125 | - Has both Client and Server |
|---|
| 126 | |
|---|
| 127 | |
|---|
| 128 | * Changes from RICE |
|---|
| 129 | |
|---|
| 130 | - Violate RFC for practical issue |
|---|
| 131 | - Don't use observer design pattern |
|---|
| 132 | - Wrote prettily |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | * Violate RFC |
|---|
| 136 | |
|---|
| 137 | - no restriction on nick length |
|---|
| 138 | -- RFC restrict nick length to 9 chars |
|---|
| 139 | - allow utf-8 nick |
|---|
| 140 | -- allow multibyte string |
|---|
| 141 | - (extendable MODE parser) |
|---|
| 142 | -- (working) |
|---|
| 143 | |
|---|
| 144 | * Don't use observer |
|---|
| 145 | |
|---|
| 146 | - Observer pattern |
|---|
| 147 | -- in the end, must write event dispatcher |
|---|
| 148 | - on_<var>event</var> is popular |
|---|
| 149 | - no more charms |
|---|
| 150 | |
|---|
| 151 | * Wrote prettily |
|---|
| 152 | |
|---|
| 153 | Write to server socket: |
|---|
| 154 | |
|---|
| 155 | >|| |
|---|
| 156 | post PRIVMSG, '#foo', 'msg' |
|---|
| 157 | post NOTICE, '#foo', 'msg' |
|---|
| 158 | ||< |
|---|
| 159 | |
|---|
| 160 | All commands are defined as constant. |
|---|
| 161 | |
|---|
| 162 | Use RFC as reference instead of net-irc reference. |
|---|
| 163 | |
|---|
| 164 | |
|---|
| 165 | * Sample Client |
|---|
| 166 | |
|---|
| 167 | >|| |
|---|
| 168 | class SimpleClient < Net::IRC::Client |
|---|
| 169 | def on_privmsg(m) |
|---|
| 170 | super |
|---|
| 171 | post NOTICE, m[0], m[1] # echo |
|---|
| 172 | end |
|---|
| 173 | end |
|---|
| 174 | |
|---|
| 175 | SimpleClient.new("host", 6667, { |
|---|
| 176 | :nick => "foobartest", |
|---|
| 177 | :user => "foobartest", |
|---|
| 178 | :real => "foobartest", |
|---|
| 179 | }).start |
|---|
| 180 | ||< |
|---|
| 181 | |
|---|
| 182 | |
|---|
| 183 | * Sample Server |
|---|
| 184 | |
|---|
| 185 | >|| |
|---|
| 186 | class Sample < Net::IRC::Server::Session |
|---|
| 187 | def on_privmsg(m) |
|---|
| 188 | super |
|---|
| 189 | post "foo!foo@host", NOTICE, m[0], m[1] # echo |
|---|
| 190 | end |
|---|
| 191 | end |
|---|
| 192 | |
|---|
| 193 | Net::IRC::Server.new(opts[:host], opts[:port], Sample, opts).start |
|---|
| 194 | ||< |
|---|
| 195 | |
|---|
| 196 | * |
|---|
| 197 | ><div class="title-leaf">< |
|---|
| 198 | Applications using net-irc |
|---|
| 199 | ></div>< |
|---|
| 200 | |
|---|
| 201 | |
|---|
| 202 | * mini-blog IRC gateways |
|---|
| 203 | |
|---|
| 204 | - Twitter (tig.rb) like TIG |
|---|
| 205 | - Wassr (wig.rb) |
|---|
| 206 | - Nowa (nig.rb) すいませんまだ使ってません |
|---|
| 207 | |
|---|
| 208 | Suitable for practical use! |
|---|
| 209 | |
|---|
| 210 | Distributed with net-irc. (examples/) |
|---|
| 211 | |
|---|
| 212 | * Lingr IRC gateway |
|---|
| 213 | |
|---|
| 214 | - Using Linger API |
|---|
| 215 | |
|---|
| 216 | Suitable for practical use! |
|---|
| 217 | |
|---|
| 218 | Distributed with net-irc. (examples/) |
|---|
| 219 | |
|---|
| 220 | でもたまに切れる。 |
|---|
| 221 | |
|---|
| 222 | *... |
|---|
| 223 | |
|---|
| 224 | examples なのはテスト書くのがめんどうだから…… |
|---|
| 225 | |
|---|
| 226 | * 昨日書いたもの |
|---|
| 227 | |
|---|
| 228 | demo |
|---|
| 229 | |
|---|
| 230 | * Citrus IRC BOT framework |
|---|
| 231 | |
|---|
| 232 | >|| |
|---|
| 233 | http://coderepos.org/share/wiki/Citrus |
|---|
| 234 | ||< |
|---|
| 235 | |
|---|
| 236 | - Has testing framework (using rspec) |
|---|
| 237 | - Supports gettext |
|---|
| 238 | - Has dynamic re-loading plugins |
|---|
| 239 | |
|---|
| 240 | coderepos++ |
|---|
| 241 | |
|---|
| 242 | * Citrus |
|---|
| 243 | |
|---|
| 244 | - Sample: chokan @freenode (registered) |
|---|
| 245 | |
|---|
| 246 | |
|---|
| 247 | * Citrus plugin |
|---|
| 248 | |
|---|
| 249 | - Plugin tests are in same file! |
|---|
| 250 | - Use RSpec |
|---|
| 251 | - DummyCore class for test |
|---|
| 252 | |
|---|
| 253 | - http://lab.lowreal.net/test/citrus/ |
|---|
| 254 | |
|---|
| 255 | |
|---|
| 256 | * Citrus plugin |
|---|
| 257 | |
|---|
| 258 | >|| |
|---|
| 259 | class SimpleReply < Citrus::Plugin |
|---|
| 260 | def on_privmsg(prefix, channel, message) |
|---|
| 261 | # do... |
|---|
| 262 | end |
|---|
| 263 | end |
|---|
| 264 | |
|---|
| 265 | test do |
|---|
| 266 | # run when test |
|---|
| 267 | describe SimpleReply do |
|---|
| 268 | before :all do |
|---|
| 269 | @core = DummyCore.new({}) |
|---|
| 270 | @socket = @core.socket |
|---|
| 271 | |
|---|
| 272 | @plugin = SimpleReply.new(@core, { |
|---|
| 273 | "SimpleReply" => { config } |
|---|
| 274 | }) |
|---|
| 275 | end |
|---|
| 276 | |
|---|
| 277 | it "should ..." do |
|---|
| 278 | end |
|---|
| 279 | end |
|---|
| 280 | end |
|---|
| 281 | ||< |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | * |
|---|
| 285 | ><div class="title-leaf">< |
|---|
| 286 | About the DSL |
|---|
| 287 | ></div>< |
|---|
| 288 | |
|---|
| 289 | * It's DSL |
|---|
| 290 | |
|---|
| 291 | >|| |
|---|
| 292 | # client |
|---|
| 293 | post PRIVMSG, "#foo", "bar" |
|---|
| 294 | |
|---|
| 295 | # server |
|---|
| 296 | post prefix, PRIVMSG, "#foo", "bar |
|---|
| 297 | ||< |
|---|
| 298 | |
|---|
| 299 | |
|---|
| 300 | * Effective utilzation of Constant |
|---|
| 301 | |
|---|
| 302 | >|| |
|---|
| 303 | PRIVMSG = 'PRIVMSG' |
|---|
| 304 | NOTICE = 'NOTICE' |
|---|
| 305 | ... |
|---|
| 306 | RPL_WELCOME = '001' |
|---|
| 307 | ||< |
|---|
| 308 | |
|---|
| 309 | I don't want to use String. |
|---|
| 310 | |
|---|
| 311 | - It mades typo. |
|---|
| 312 | - It is not pretty. |
|---|
| 313 | |
|---|
| 314 | * |
|---|
| 315 | ><div class="title-leaf">< |
|---|
| 316 | DSL in the language |
|---|
| 317 | ></div>< |
|---|
| 318 | |
|---|
| 319 | |
|---|
| 320 | * ... |
|---|
| 321 | |
|---|
| 322 | >|| |
|---|
| 323 | post PRIVMSG, "#foo", "bar" |
|---|
| 324 | ||< |
|---|
| 325 | |
|---|
| 326 | DSL...? |
|---|
| 327 | |
|---|
| 328 | Maybe not. |
|---|
| 329 | |
|---|
| 330 | * |
|---|
| 331 | |
|---|
| 332 | Often, I try to make DSL. |
|---|
| 333 | |
|---|
| 334 | But I assessed that DSL is irrelevance for this library.. |
|---|
| 335 | |
|---|
| 336 | |
|---|
| 337 | * DSL bad example |
|---|
| 338 | |
|---|
| 339 | - scrAPI |
|---|
| 340 | |
|---|
| 341 | >|| |
|---|
| 342 | ebay_auction = Scraper.define do |
|---|
| 343 | process "h3.ens>a", :description=>:text, :url=>"@href" |
|---|
| 344 | process "td.ebcPr>span", :price=>:text |
|---|
| 345 | process "div.ebPicture>a>img", :image=>"@src" |
|---|
| 346 | result :description, :url, :price, :image |
|---|
| 347 | end |
|---|
| 348 | ||< |
|---|
| 349 | |
|---|
| 350 | Can't understand the purpose at first view. |
|---|
| 351 | |
|---|
| 352 | 某所で scrAPI なコードをメンテしたとき発狂しそうだった |
|---|
| 353 | |
|---|
| 354 | * DSL bad example - scrAPI |
|---|
| 355 | |
|---|
| 356 | - what is second argument of process |
|---|
| 357 | - need to look the reference |
|---|
| 358 | - lerning cost > convenience |
|---|
| 359 | - mechanize and hpricot is better |
|---|
| 360 | |
|---|
| 361 | |
|---|
| 362 | * DSL good examples |
|---|
| 363 | |
|---|
| 364 | - Rake |
|---|
| 365 | - RSpec |
|---|
| 366 | |
|---|
| 367 | |
|---|
| 368 | * DSL good examples - Rake |
|---|
| 369 | |
|---|
| 370 | >|| |
|---|
| 371 | desc "Publish to RubyForge" |
|---|
| 372 | task :rubyforge => [:rdoc, :package] do |
|---|
| 373 | require 'rubyforge' |
|---|
| 374 | Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'fobar').upload |
|---|
| 375 | end |
|---|
| 376 | ||< |
|---|
| 377 | |
|---|
| 378 | Good example of hash arrow to represent dependency. |
|---|
| 379 | |
|---|
| 380 | |
|---|
| 381 | * DSL good examples - RSpec |
|---|
| 382 | |
|---|
| 383 | >|| |
|---|
| 384 | obj.should == "foo" |
|---|
| 385 | foo.should be_true |
|---|
| 386 | ||< |
|---|
| 387 | |
|---|
| 388 | Easy to read, easy to write. |
|---|
| 389 | |
|---|
| 390 | |
|---|
| 391 | * DSL good examples |
|---|
| 392 | |
|---|
| 393 | - Rake |
|---|
| 394 | - RSpec |
|---|
| 395 | |
|---|
| 396 | Can understand the purpose at first view! |
|---|
| 397 | |
|---|
| 398 | |
|---|
| 399 | * So, DSL requires... |
|---|
| 400 | |
|---|
| 401 | - Readable! |
|---|
| 402 | -- not requires precedent |
|---|
| 403 | - Writable! |
|---|
| 404 | -- not relying on reference |
|---|
| 405 | |
|---|
| 406 | * DSL's problems |
|---|
| 407 | |
|---|
| 408 | - hard to trace process |
|---|
| 409 | - hard to know Class defining the method |
|---|
| 410 | - IT IS A LANGUAGE. |
|---|
| 411 | -- It is difficult to design a language. |
|---|
| 412 | |
|---|
| 413 | |
|---|
| 414 | * |
|---|
| 415 | |
|---|
| 416 | Any sufficiently designed DSL is indistinguishable from NEW language. |
|---|
| 417 | |
|---|
| 418 | 高度に発達した DSL は新言語と見分けがつかない |
|---|
| 419 | |
|---|
| 420 | |
|---|
| 421 | * |
|---|
| 422 | |
|---|
| 423 | Think before using DSL! |
|---|
| 424 | |
|---|
| 425 | |
|---|
| 426 | * End |
|---|
| 427 | |
|---|
| 428 | Thank you |
|---|