175
みんなが 楽しくプログラミング 出来る魔法

Having Fun Programming!

Embed Size (px)

Citation preview

みんなが楽しくプログラミング

出来る魔法

Have Fun Programming

Programming for Fun!

@tenderlove

たこ焼き仮面

ひげの山男

そして

その正体は...

Aaron Patterson

AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.

First

ゲスト出演

Ujihisa!

Q: How can I enjoy

programming?

http://www.flickr.com/photos/recompile_net/3733132232/

A: Use Vim!

http://www.flickr.com/photos/recompile_net/3732334373/

本日の概要

•言語•環境•研究課題•進化

幼少時代

学生時代

プログラマ時代

10年後

喜 び

Rubyと!

言語

人類言語

人類言語

コンピュータ言語

アイディアの伝達

タコ焼きを作ろう!

アイディアの伝達

class タコ焼きend6.times { タコ焼き.new

}

思考

ビールを飲みながら、宿題すれば良いかな。

思考

Thread.new do ビール.飲む()

endThread.new do 宿題.する()

end(Thread.list -[Thread.main]).each { |x| x.join }

プログラミング言語

通常使われる言語

•Ruby

•C

• Java

• Lisp

• PHP?

プログラミング言語でポリグロットは普通

人間の言葉

We Speak

•英語•日本語•フランス語•ドイツ語

話し言葉.count

対書き言葉.count

;_;";_;".encode(英語) # => ":'("

言語は思想を入れる箱

多様な入力=

多様な出力

言葉の入力が人にとっての起爆剤となる

人間は優しいパーサーを実装した翻訳機

環境

テキストエディタじゃなくて!

実際に存在する場所

バスで

電車で

公園で

お風呂で

自分と一緒に

帽子 / かつら

花の帽子

かつら

ロシア人の制帽

変身

Ruby Brigades

Seattle.rb

Hack Night

挑戦

改良

協力

教える/教わる

ケーキ!!!!

ケーキ!

ケーキ!

会議

Hallway Track

ヘルプデスク

出会った人々は、•ドイツ•スイス•ブラジル•ウルグアイ•その他、沢山の国!

手伝った内容

•Rails 3の二つのバグ

•エンコディーングの説明• XMLの解析

• YAMLの解析

0 bugs in Ruby 1.9

50% used Ruby 1.9

人同士のつながり

研究課題

YAMLPsych と Syck

Syck

•Ruby 1.8 と 1.9

• YAML 1.0 (ほとんど) parserとemitter

•ホワイ著

Psych

•Ruby >= 1.9.2 のみ

• libyamlラッパー

• YAML 1.1 parser と emitter

•タコ焼き仮面著

YAMLの解析使用途

Ruby 1.8 / 1.9

require 'yaml'

YAML.load_file('some_file.yml')YAML.load('--- hello world!')

Ruby 1.9.2 / Psych

require 'psych'

Psych.load_file('some_file.yml')Psych.load('--- hello world!')

1.9.2 Opt-in

require 'yaml'

YAML::ENGINE.yamler = 'psych'

YAML.load('--- this is psych')

YAMLのダンプ法

require 'psych'

Psych.dump { :foo => 'bar' }{ :hello => 'world' }.to_yaml

JSONにダンプ?

---foo: bar

YAML Map

---'foo': 'bar'

YAML Map

---{ 'foo': 'bar' }

YAML Map

require 'psych'

Psych.to_json { :foo => 'bar' }

Psychで遊ぼう

Emitterのカスタム化

class Foo def initialize @greeting = 'world' end

def encode_with(coder) coder['hello'] = @greeting end

def init_with(coder) @greeting = coder['hello'] endend

--- !ruby/object:Foohello: world

Psych.dump

Psych.load

#<Foo:0x000001009f6770 @greeting="world">

class Foo def initialize @greeting = 'world' end

def encode_with(coder) coder['hello'] = @greeting end

def init_with(coder) @greeting = coder['hello'] endend

Independentの初期化

YAML と JSON

Psych.dump Foo.newPsych.to_json Foo.new

class XMLDumper < Psych::Handler def self.dump(object) dumper = new viz = Psych::Visitors::YAMLTree.new({}, dumper) viz << object dumper.doc.to_xml end

attr_reader :doc

def initialize @doc = Nokogiri::XML::Document.new @doc.root = @doc.create_element 'root' @tags = [] @stack = [@doc.root] end

def start_mapping(anchor, tag, implicit, style) tag = @doc.create_element('table') @stack.last << tag @stack << tag end

def end_mapping @stack.pop end

def scalar(value, anchor, tag, *args) @stack.last << @doc.create_element('tr').tap do |tag| tag << @doc.create_element('td', value) end endend

YAML, JSON と

XML

Psych.dump Foo.newPsych.to_json Foo.newXMLDumper.dump Foo.new

class HTMLDumper < XMLDumper def initialize @doc = Nokogiri::HTML::Document.new @doc.root = @doc.create_element('html') @doc.root << @doc.create_element('body') @tags = [] @stack = [@doc.root.children.first] endend

YAML, JSON, XML と HTML

Psych.dump Foo.newPsych.to_json Foo.newXMLDumper.dump Foo.newHTMLDumper.dump Foo.new

module Marshalable module ClassMethods def _load data x = allocate x.init_with Marshal.load data x end end

def self.included klass klass.extend ClassMethods end

def _dump o coder = {} encode_with coder Marshal.dump coder endend

class Foo; include Marshalable; end

YAML, JSON, XML, HTML と Marshal

Psych.dump Foo.newPsych.to_json Foo.newXMLDumper.dump Foo.newHTMLDumper.dump Foo.newMarshal.dump Foo.new

今なら2つのメソッド価格で5フォーマットとお買い得!

それは冗談今だけではないし、

無料です

SQLite3-Ruby

SQLite3-Ruby

• SQLite3 ラッパー

• Jamis Buck 原著

• SWIG

方法

require 'sqlite3'

connection = SQLite3::Database.new('file.sqlite3')

コネクションの設立

require 'sqlite3'

connection = SQLite3::Database.new(':memory:')

メモリの内部Pro Tip

require 'sqlite3'

connection = SQLite3::Database.new(':memory:')

メモリの内部Pro Tip

クエリの作成

connection.execute('CREATE TABLE foo(id INTEGER)')

connection.execute('INSERT INTO foo (id) VALUES (?)', [10])

ステートメントの用意

stmt = connection.prepare('SELECT * FROM foo WHERE id = ?')

stmt.bind_param(1, 10)

stmt.each do |row| p rowend

どうして?

ステートメントがキャッシュできる為

パフォーマンスの向上のあり得る!

SQLite3で遊ぼう!

•その1: APIを読もう

•その2: 自分のコードを書こう

•その3: 友達を困らせよう

struct sqlite3_vfs { int iVersion; /* Structure version number */ int szOsFile; /* Size of subclassed sqlite3_file */ int mxPathname; /* Maximum file pathname length */ sqlite3_vfs *pNext; /* Next registered VFS */ const char *zName; /* Name of this virtual file system */ void *pAppData; /* Pointer to application-specific data */ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, int flags, int *pOutFlags); int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); void (*xDlClose)(sqlite3_vfs*, void*); int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); int (*xSleep)(sqlite3_vfs*, int microseconds); int (*xCurrentTime)(sqlite3_vfs*, double*); int (*xGetLastError)(sqlite3_vfs*, int, char *); /* New fields may be appended in figure versions. The iVersion ** value will increment whenever this happens. */};

その1: APIを読もう

IO Hooks

その2: 自分のコードを書こう

static int rbFile_close(sqlite3_file * ctx){ rubyFilePtr rfile = (rubyFilePtr)ctx; VALUE file = rfile->file; rb_funcall(file, rb_intern("close"), 0); return SQLITE_OK;}

class VFS < SQLite3::VFS def open(name, flags) OurFile.new(name, flags) endend

class OurFile def read(...); ... end def write(...); ... endend

SQLite Database は何でも格納出来る

__END__ + DATA

class EvilVFS < SQLite3::VFS def open name, flags DATABase.new name, flags endend

class DATABase < SQLite3::VFS::File def initialize name, flags super @store = File.open(name, File::RDWR | File::CREAT) @offset = 0

if File.expand_path(__FILE__) == name @store.seek DATA.pos @offset = DATA.pos end end

def close @store.close end

def read amt, offset @store.seek(offset + @offset) @store.read amt end

def write data, offset @store.seek(offset + @offset) @store.write data end

def sync opts @store.fsync end

def file_size File.size(@store.path) - @offset endend

SQLite3.vfs_register(EvilVFS.new)db = SQLite3::Database.new(__FILE__, nil, 'EvilVFS')

db.execute(<<-eosql) create table if not exists users(id integer primary key, name string)eosql

100.times { db.execute(<<-eosql, 'tenderlove') insert into users(name) values (?) eosql}

p db.execute('select count(*) from users')

__END__

その3: 友達を困らせよう

ソースコードはここhttp://gist.github.com/319224/

SQLite3-Rubyの新機能

楽しい新情報

•Ruby 1.9 エンコーディングサポート

• 1000倍スピードアップ(か、なんか)

エンコーディングrequire 'sqlite3'

db = SQLite3::Database.new(':memory:')

db.execute('CREATE TABLE foo(id INTEGER, name VARCHAR)')db.execute('INSERT INTO foo (id, name) VALUES (?,?)',[10,'hello world'])

rows = db.execute('SELECT name FROM foo')p rows.first.first.encoding # => #<Encoding:UTF-8>

Encoding.default_internal = 'EUC-JP'

rows = db.execute('SELECT name FROM foo')p rows.first.first.encoding # => #<Encoding:EUC-JP>

エンコーディングrequire 'sqlite3'

db = SQLite3::Database.new(':memory:')

db.execute('CREATE TABLE foo(id INTEGER, name VARCHAR)')db.execute('INSERT INTO foo (id, name) VALUES (?,?)',[10,'hello world'])

rows = db.execute('SELECT name FROM foo')p rows.first.first.encoding # => #<Encoding:UTF-8>

Encoding.default_internal = 'EUC-JP'

rows = db.execute('SELECT name FROM foo')p rows.first.first.encoding # => #<Encoding:EUC-JP>

エンコーディングrequire 'sqlite3'

db = SQLite3::Database.new(':memory:')

db.execute('CREATE TABLE foo(id INTEGER, name VARCHAR)')db.execute('INSERT INTO foo (id, name) VALUES (?,?)',[10,'hello world'])

rows = db.execute('SELECT name FROM foo')p rows.first.first.encoding # => #<Encoding:UTF-8>

Encoding.default_internal = 'EUC-JP'

rows = db.execute('SELECT name FROM foo')p rows.first.first.encoding # => #<Encoding:EUC-JP>

速度比較 (SELECT汎用)

0.01

0.1

1

10

100

1000

500 1000 1500 2000 2500 3000 3500

1.2.5 1.3.0

PHP + Ruby

Phuby!

Ruby.PHP()

Phuby::Runtime.php do |rt| rt.eval('$v = strlen("PHP IS AWESOME");') puts rt['v'] # => 14end

Ruby.PHP()

Phuby::Runtime.php do |rt| rt.eval('$foo = array();') rt.eval('$foo["hello"] = "world";')

foo = rt['foo'] # => #<Phuby::Array:0x101f8f848> p foo['hello'] # => ‘world’end

$PHP->Ruby();

class FUN def times puts "hello" endend

Phuby::Runtime.php do |rt| rt['fun'] = FUN.new rt.eval('$fun->times();') # => helloend

PHPランタイム

どうやって?

弱い参照のテーブル

VariableはRubyから

PHPに旅行する

rt['foo'] = Foo.new

Ruby C PHP

PHPProxy(runtime)

WeakReference

Table

Ruby

Ruby C PHP

PHPProxy(runtime)

WeakReference

Table

Ruby

PHPからRubyに呼び出す

$foo->bar();

Ruby C PHP

PHPProxy(runtime)

WeakReference

Table

Ruby

Ruby C PHP

PHPProxy(runtime)

WeakReference

Table

Ruby

RubyからPHPに呼び出す

rt['foo'].bar()

Ruby C PHP

PHPProxy(runtime)

Ruby

Ruby C PHP

PHPProxy(runtime)

Ruby

Proxy(object)

Phubyで遊ぼう

PHP + WEBrick=

Blog

#!/usr/bin/env ruby

require 'rubygems'require 'phuby'require 'rack'

### Rack::Phrack is a Rack handler that will evaulate and serve PHP files.

class Rack::Phrack < Rack::File class Events < Struct.new(:code, :headers, :body) def write string; body << string; end def send_headers response_code; end

def header value, op k, v = value.split(': ', 2) self.code = 302 if k == 'Location' headers[k] = [headers[k], Rack::Utils.unescape(v)].compact.join "\n" end end

def call env events = Events.new 200, {}, '' file = File.join @root, env['PATH_INFO'] file = File.join file, "index.php" if File.directory?(file)

return super unless file =~ /php$/

Dir.chdir(File.dirname(file)) do Phuby::Runtime.php do |rt| rt.eval "date_default_timezone_set('America/Los_Angeles');" # *shrug*

{ Rack::Utils.parse_query(env['QUERY_STRING']) => "_GET", Rack::Utils.parse_query(env['rack.input'].read) => "_POST", Rack::Utils.parse_query(env['HTTP_COOKIE'], ';') => "_COOKIE", }.each do |from, to| from.each { |k,v| rt[to][k] = v } end

env.each { |k,v| rt['_SERVER'][k] = v || '' unless k =~ /^rack/ } rt["_SERVER"]['REQUEST_URI'] = env['PATH_INFO']

rt.with_events(events) { open(file) { |f| rt.eval f } } # RUN! end end events.to_a endend

Rack::Handler::WEBrick.run(Rack::Phrack.new(ARGV[0] || Dir.pwd), :Port => 10101)

Client

Phrack

PHPRuntime

Client

Phrack

PHPRuntime

進化

コードの品質

変更を恐れるな

失敗を恐れるな

「出来るかどうかやってみよう」

自分自身への挑戦

Special Thanks!

フログラマーaka @masuidrive

zenspider

Special Request

One Click Installer

Luis Lavena

ご清聴有難うございました

ご質問は?