読者です 読者をやめる 読者になる 読者になる

force_ssl = true 時のリダイレクトループ [Rails]

環境 ubuntu: 16.04, rails: 4.2.6, nginx: 1.4.6

Rails において https 通信を強制するには config/environments/production.rb 中の config.force_ssl = true をコメントアウトすればいいが、nginx でも https 転送の設定をしているとリダイレクトの無限ループに陥ってしまう。
nginx だけでも良いのだけれど、リンクやリダイレクトなどの rails 内部の処理が http で処理されるため、それらもいちいち nginx でリダイレクトするのがうっとうしいし、ログも肥大化する。
nginx の設定ファイルを書き換えることで対処できる。
参考: Nginx + SSL + Rails -- BONNOH FRACTION 14
パスは私の環境に依っている。

# /etc/nginx/conf.d/rails.conf
server {

# ...

location @unicorn {
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;

  # この行を追加
  proxy_set_header X-FORWARDED_PROTO https;

  proxy_pass http://unicorn;
}

rails と nginx を再起動して、反映させる。

メタプログラミングRuby まとめ [学習メモ]

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

本書は ruby におけるメタプログラミングを扱った本で、ruby と言うことをのぞいても貴重なメタプログラミングの資料だ。
メタプログラミングとは「プログラムを書くプログラム」を書くプログラミング手法のことで、有名なところでLisp 族におけるマクロがある。
Lisp におけるメタプログラミングの教科書が「On Lisp」ならば、この本は ruby での最右翼だろう。
高級感のある表紙と厚くない分量はやる気をそぐことがない。
文章も対話形式で読みやすく、しばしば挟まれるクイズも技量の定着に一役買う。
メタプログラミング、と題名にはあるが、lisp におけるメタプログラミングがマクロではっきりと区切られているのに対して ruby においてその境界ははしばしば曖昧だ。
ruby におけるダイナミックなコーディング法を細かく解説してあり、全く新しい方法を学ぶ、というよりもこれまで曖昧だった ruby の深い仕組みへの理解を助けられたように思う。
これまで私は ruby は一部の人間が行き当たりばったりに仕様を決めた、使いやすいが安っぽい rails 用言語、のようなイメージがあったところだが、本書を読んで実は一貫した仕組みを備えている精緻な言語ことが分かってきたように感じる。

内容にあった動的なメソッド定義やスコープの切り替えなどはよく使うようになった。
しかし、多くの内容はいくらかの思考の飛躍が必要で、意識的に使おうとしないと永遠に使うことはないだろう。
本書は非常に難解と言うわけではないが、初心者向けでもないし、実際の所主人公のボブのように一週間で終えるのも難しいだろう。
完全に物にするには本棚に置いて何度か読み返す必要があり、またその価値がある。
背表紙も美しいので、見栄えも悪くない。

本書で書かれているメタプログラミングを使う究極の目的はコードの重複を極限まで削ることにあるのだろうと思う。
コードが短く、抽象的に、高密度になればバグの頻度が下がり、読みやすくなり、何より、楽しい。
それは ruby 自体が目指すものと近いのかもしれない。

sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp
sym.hateblo.jp

メタプログラミングRuby その10 [学習メモ]

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

金曜日 : コードを記述するコード

6.2 Kernel#eval

プログラムを記述するコードをもっとも単純に実行するには、プログラムを文字列で生成してそれを実行すればよい。
eval メソッドはそれを可能にする。

s = "puts 'hello'"

eval s
# => hello

任意コード実行はいつだってセキュリティホールにつながるが、それに近い物を感じる。
外部からの文字列を受け取らないようにすべきなのだろう。

6.7 フックメソッド

ruby ではインスタンスの生成時、クラスの継承が起こった時などにコードを実行させることができる。

class String
  def self.inherited(subclass)
    puts "#{self}#{subclass} に継承された"
  end
end

class MyString < String; end
# => String は MyString に継承された

これらフックメソッドは考えられるだけのタイミングで定義することができる。

本章はクイズや実際の gem での例が中心となっている。
(本の中では)一週間の学習が終わり、これで本書も一区切りと言ったところだ。
この後は豪華な付録?として rails 内部のメタプログラミングを見ていくことになる。
もっとも有名な gem である rails は私を含め多くの人が ruby に触れるきっかけとなったライブラリであり、何か感慨深い物がある。

Ruby から OpenGL を使う

環境 : ruby 2.3.0 OSX 10.9.5

opengl は汎用的な CG 作成ソフトウェアで、ruby からも利用できる。
gem を探すと openglruby-opengl の二種類あるが、ruby-opengl の方は数年前から更新が止まっていて、使い方も少し違うので opengl の方を使う。
公式サイト https://rubygems.org/gems/opengl
いつも通り

sudo gem install opengl glu glut

後ろの2つもインストールする必要がある。
最初はなかなかインストールがうまくいかなかったが、gem update をしたら通った。
依存に原因があったのだろうか。
hello world 代わりにポットを描いてみよう。
参考: MF / Ruby で OpenGL

require 'opengl'
require 'glut'

display = proc{
  GL.Clear(GL::COLOR_BUFFER_BIT)
  GL.Color3f(1, 1, 1)
  GLUT.WireTeapot(0.5)
  GL.Flush()
}

GLUT.Init()
GLUT.InitWindowSize(480,480)
GLUT.CreateWindow("OpenGL Example")
GLUT.DisplayFunc(display)
GL.ClearColor(0,0,0,1)
GLUT.MainLoop()

f:id:gensym:20160917121519p:plain


gem に examples が付いているので、いくつかやってみる。
examples/misc/plane.rb

f:id:gensym:20160916194338p:plain
examples/misc/anisotropic.rb

f:id:gensym:20160916194347p:plain


examples/OrangeBook/brick.rb

f:id:gensym:20160916194357p:plain


opengl 自体がなかなか複雑なので、ruby を通しても面倒な記述が必要なようだ。

メタプログラミングRuby その9 [学習メモ]

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

5.4.1 特異クラスの謎
特異メソッドはオブジェクトにメソッドを定義するが、メソッドはオブジェクトに所属することはできない。
しかし、いずれかの既存のクラスに所属してしまうとオブジェクト特異的とは行かなくなる。
そこで、ruby は特異メソッドに対応した特異クラスというクラスを作り、そこに特異メソッドが所属することになる。
特異クラスは普段隠蔽されており、特別な方法でしか知ることができない。
singleton_class メソッドが一番手軽だ。

name = "Bob"

def name.hello
  puts "hello, #{self}!"
end

name.singleton_class
# => #<Class:#<String:0x007ff61a2cd090>>
name.singleton_class.instance_methods false
# => [:hello]
name.singleton_class.superclass
# => String

普通とは違った表示になる。
特異クラスはインスタンスを1つしか持てず(ここでは name)、オブジェクトに紐付いた特異メソッドが所属する。
また、特異クラスのスーパークラスはオブジェクトのクラスになる。
つまり、メソッド探索においてまずはオブジェクトの特異クラスから探索し、その後にオブジェクトのクラスと移っていくことになる。

5.4.4 特異クラスと継承
特異クラスのスーパークラスはもとのクラスのスーパークラスの特異クラスだ。
なにやらこんがらがりそうだが、整理してみよう。

class C
  def self.hello
    puts "hello"
  end
end

class D < C; end

C.singleton_class
# => #<Class:C>
D.singleton_class
# => #<Class:D>

D.singleton_class.superclass
# => #<Class:C> # C ではない!
C.singleton_class.superclass
# => #<Class:Object>
D.hello
# => hello

なぜこのようにややこしくなっているかというと、こうすることによってサブクラスから暮らすメソッドが呼び出せるようになるからだ。

5.6 メソッドラッパー

組み込みや外部ライブラリのメソッドがブラックボックス的になっているときに、周囲に機能を追加したいときにはどうすればいいのか?
5.6.1 アラウンドエイリアス
すでにあるメソッドにエイリアス(別名)をつけて、新たな機能を追加したメソッドで再定義すればよい。
たとえば String クラスの reverse メソッドに呼び出された回数を追加する機能をつけたいとする。

class String
  alias_method :old_reverse, :reverse

  def reverse
    inc_counter
    # カウンターを増加させるメソッド
    old_reverse
  end
end

"hello".reverse
# => olleh

もとの機能を損なわずに、カウント機能を追加することが出来た。

5.6.2 さらにメソッドラッパー
上のやり方だとエイリアスでクラスの名前空間を汚染してしまう恐れがある。
2章で登場した Refinements を使うことで使用範囲を限定するのが安全な方法かもしれない。

module StringRefine
  refine String do
    def reverse
      super "esrever"
    end
  end
end

using StringRefine
"hello".reverse
# => esrever

メタプログラミングRuby その8 [学習メモ]

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

第5章 木曜日 : クラス定義

5.1.2 カレントクラス

ruby プログラムが常にカレントオブジェクト self を持っているように、カレントクラス(モジュール)も持っている。
しかしカレントクラスには self のように直接アクセスできるキーワードはない。
class_eval 関数は与えられたクラスのコンテキストでブロックを評価することが出来る。

def add_method_to(cl)
  cl.class_eval do
    def m; 'Hello'; end
  end
end

add_method_to "abc".class
"abc".m
# => Hello

class でクラスを再オープンして同様のことをするにはクラス名の定数が必要だが、 class_eval の場合は変数を受けとることが出来るので、動的なメソッド定義が可能になる。
また class_eval はフラットスコープなので、ブロック外部の値を使うことが出来る。

5.1.3 クラスインスタンス変数

ruby における self はわかりにくい。
python の様に頻出するわけではないが、それ故に役割が見えにくくなる。
self は自身のクラスであり、インスタンスとは関係がない。なので

class MyClass
  @name = "Tom"
  def self.hello
    puts "hello, #{@name}!"
  end
end

MyClass.hello "Tom"
# => Hello, Tom!

となる。インスタンスを作ってから呼び出すわけではない。

5.3 特異メソッド

特異メソッドとは、特定のオブジェクトに特異的に定義されるメソッドだ。

name = "Alice"

def name.hello
  puts "hello, #{name}!"
end

name.hello
# => Hello, Alice!

使い方が難しいような特異メソッドだが、本質的にクラスメソッドと同じもので、定義も同じようにできる。

def obj.singleton_method; end
# 特異メソッド
def MyClass.class_method; end
# クラスメソッド

発酵の技法 [読書メモ]

発酵の技法 ―世界の発酵食品と発酵文化の探求 (Make:Japan Books)

発酵の技法 ―世界の発酵食品と発酵文化の探求 (Make:Japan Books)

まさかのオライリーからの出版だ。
新刊リストに載っていたときは新たなプログラミング手法の本なのかと思ったが、コンピュータとは全く関係がないれっきとした発酵食品に関する本だった。

発酵食品の専門家である筆者が世界の発酵食品の歴史的背景、レシピを集め実際に自分で作って見た詳細やコツなどが記されていてかなり読み応えのある本となっている。
紹介される内容も納豆、味噌など日本人にもなじみの深い物からバナナの葉で豆を包んで作るテンペなど多岐にわたる。
最初からじっくりと読んでもいいし、リファレンス的な使い方もできそうだ。
写真を眺めるのも楽しい。

この手の食品本にありがちな科学的根拠のない話を書き連ねて対象を神格化するようなこともなく、発酵食品に対する愛を感じさせつつも知的な誠実さを保っており筆者には好感を持てた。

何より読み物として面白く、これまであまり発酵食品になじみがなかった私のような読者にも本のレシピを試させるような力のある本だと思う。