Dired でバイナリファイルを開くときに本当に開くか確認する何か

環境

動機

Emacsでは写真やらPDFやらをEmacs内で見れるイッてる機能があります.
しかし,写真やらPDF開こうとすると数秒かかって非常に辛いです. さらに,Diredを使っているとよく押し間違えてPDFを開いてしまい,数秒待ったあとkill-bufferするみたいなことによくなります. これが非常に辛いのでなんとかしたいということで書きました.

実際

(defun util/same-ext? (file-path ext)
  "Check same exntion or not."
  (let ((file-ext (file-name-extension file-path)))
    (if file-ext
        (string= (downcase file-ext) ext))))

(defun util/chomp (str)
  (replace-regexp-in-string "[\n\r]" "" str))

(setq dired-open-whitelist '("c" "coffee" "clj" "el"
                             "ex" "exs" "go" "h" "hs"
                             "html" "js" "ml" "md" "rb"
                             "yml" "scala" "slim" "scss"))

(defun dired/binary? ()
  (let ((cmd (format "nkf -g %s" (dired/filename-at-point))))
    (string= "BINARY" (util/chomp (shell-command-to-string cmd)))))

(defun dired/filename-at-point ()
  (car (dired-get-marked-files 'no-dir)))

(defun dired/directory? ()
   (file-directory-p (car (dired-get-marked-files))))

(defun dired/include-whitelist? (filename whitelist)
  (if whitelist
      (or (util/same-ext? filename (car whitelist))
          (dired/include-whitelist? filename (cdr whitelist)))))

(defun dired-file-open-or-not ()
  "File open if file type is directory or file exntion is in whitelist or file is not binary."
  (interactive)
  (let ((ext-lst dired-open-whitelist)
        (filename (dired/filename-at-point)))
    (if (or (dired/directory?)
            (dired/include-whitelist? filename ext-lst)
            (not (dired/binary?)))
        (dired-find-file)
      (if (yes-or-no-p (format "Do you really open? %s" filename))
          (dired-find-file)))))

後は

(define-key dired-mode-map (kbd "C-f") 'dired-file-open-or-not)

何をしたか

開くのに時間がかかりそうなファイルを開いていいかどうかを聞くようにしました.

ファイルがBINARYかどうかをnkfで確認してます. しかし,毎回nkfを叩くのは辛いので以下の条件の時はnkfを叩かずそのままファイルを開いています.

  • ディレクトリの時
  • whitelistで定義された拡張子のファイルの時

感想

これを書いてたら何故か時間が消えていったが後悔はしていない

emacsからalcでの単語検索を楽にする

emacsからアルクで単語検索する便利コマンド書いた

環境
コード
(defsubst marked-input ()
  (when (use-region-p)
    (buffer-substring-no-properties (region-beginning) (region-end))))

(defun search-word-in-alc ()
  (interactive)
  (let* ((cmd "open \"%s\"")
         (url (format "http://eow.alc.co.jp/search?q=%s"
                      (or (marked-input) (read-shell-command "word: ")))))
    (shell-command-to-string
     (format cmd url))))

(global-set-key (kbd "s-E") 'search-word-in-alc)

ちなみにzshバージョンもある

function search-word-in-alc() {
    url="http://eow.alc.co.jp/search?q="
    open "${url}$1"
}
alias e='search-word-in-alc'

エスケープ処理とか全くしてないので動きが怪しいこともある気がするけどそこそこ便利!!!

RubyでDSLを書く

Rackのコードを読んでたらDSL使ってたのでその部分. instance_evalを使ってBuilderクラス内でblockを実行するようにしている.

つまり以下のプログラムは,Builderのインスタンス内で呼ばれたことになってる.

  map '/' do
    {
      'Content-Type' => 'text/plain',
      'status' => 200,
      'body' => 'this is root!'
    }
  end
class Builder
  def initialize(&block)
    instance_eval(&block) if block_given?
  end

  def map(path, &block)
    set(:get, path, block)
  end

  def get(path)
    key = [:get, path]
    route_table[key].call
  end

  private

  def set(name, path, block)
    key = [name, path]
    route_table[key] = block
  end

  def route_table
    @route_table ||= {}
  end
end

app = Builder.new do
  map '/' do
    {
      'Content-Type' => 'text/plain',
      'status' => 200,
      'body' => 'this is root!'
    }
  end
end

p app.get('/')
# => {"Content-Type"=>"text/plain", "status"=>200, "body"=>"this is root!"}

まとめ

最高の夏

参考

http://ref.xaio.jp/ruby/classes/object/instance_eval

Rubyでプラグイン機構を作る

rack/rack · GitHub のコード読んでてプラグイン(Rackの場合はバックエンドにどのサーバを使うか)の処理があったので取り出して書いてみた.

Rubyではクラスは定数なのでHandlerっていう名前空間の中の定数を探すだけでいい.

# sample1.rb
module Handler
  class Base
    def call
      run
    end

    def run
      raise NotImplementedError
    end
  end

  class PlugA < Base
    def run
      p "called in A"
    end
  end
end

# sample2.rb
module Handler
  class PlugB < Base
    def run
      p "called in B"
    end
  end
end

# runner.rb
require_relative './sample1.rb'
require_relative './sample2.rb'

def run(class_name)
  klass = Handler.const_get(class_name)
  klass.new.call
end

['PlugA', 'PlugB'].each do |e|
  run e
end

# => "called in A"
# => "called in B"

githubの分割バージョンがある

github.com

感想

研究室にyogiboがあってそれに乗っかりながらだらだら読んでて、夏休みの朝に再放送のアニメ見てる感じだった

RubyのStructの簡易版実装してみた

30分くらいでできる簡単な問題探しててmzpさんのやつを見つけてそれを解いてみてる.

これが動けばいい

Dog = MyStruct.new(:name, :age)
fred = Dog.new('fred', 5)
fred.age = 6
printf "name:%s age:%d\n", fred.name, fred.age

回答

class MyStruct
  def self.new(*names)
    Class.new do |_obj|
      def initialize(*values)
        @__values = values
      end

      names.each_with_index do |method, i|
        class_eval <<-EOS
          def #{method}
             @__values[#{i}]
          end

          def #{method}=(value)
             @__values[#{i}] = value
          end
        EOS
      end
    end
  end
end

参考

30分プログラムリスト - みずぴー日記

モナディックなパーザーコンビネータ作ってみた

タイトル通りで作ってみたました. もともと研究で違うことやってたはずなのに目的を見失ってなんか面白そうだしこれならゼミで話しても怒られなさそうという考えからこの頃ずっと勉強してた.

OCamlで実装しようかHaskellで実装しようか迷っててどっちでも良かったんだけど最終的にはHaskellで書いた. 最初はOCamlの勉強も少ししてて、とにかく本を買いたくなかったので以下のページを読んでた.

けど素直にHaskellでやったほうが楽そうという気持ちになり途中からHaskellに切り替えた. Haskellの文法は雰囲気がわかる程度だったのでなんとかなるだろうと思い特に何もしなかった. モナドは「モナドは単なる自己関手の圏におけるモノイド対象だよ。何か問題でも?」という感じだったので以下のページを読んでだ.

パーザーコンビネータググるといろんな人が実装しててるのでそれを参考にするといいかもしれない. こんなふうにParserの型が決まった時点で考えることはあんまりなくて型すごいって思いながら実装しいくとできたし型すごい.

type Result = Either String
type Parser v = StateT String Result v

PEGパーザにした気でいるんですがもしかしたらこれではいけないかもしれないので間違っていたらスマンという感じです.

import Control.Monad.State
import GHC.Base((<|>))
import Data.Char

type Result = Either String

type Parser v = StateT String Result v

runParser = runStateT

look :: Parser Char
look = do
  x:_ <- get
  return x

item :: Parser Char
item = do
  x:xs <- get
  put xs
  return x

satisfy :: (Char -> Bool) -> Parser Char
satisfy f = do
  a <- item
  if f a then return a else mzero

unsatisfy :: (Char -> Bool) -> Parser Char
unsatisfy f = satisfy (not . f)

cjoin :: Parser a -> Parser a -> Parser [a]
cjoin p1 p2 = do
  a <- p1
  b <- p2
  return [a, b]

select :: Parser a -> Parser a -> Parser a
select = (<|>)

many :: Parser a -> Parser [a]
many f = many1 f <|> return []

many1 :: Parser a -> Parser [a]
many1 f = do
  a <- f
  b <- many f
  return $ a:b

例えばExpr <- Number + Numberを受理するためのは以下のように書くとちゃんと計算結果が返ってくる.

number :: Parser Integer
number = do
  n <- many1 digit
  return $ read n
  where digit = satisfy isDigit

expr :: Parser Integer
expr = do
  a <- number
  op <- token (=='+') >> return (+)
  b <- number
  return $ op a b

main :: IO ()
main = print $ runStateT expr2 "1+2;" -- => Right (3,";")

4則演算バージョンがあるのでぜひ

sample.hs · GitHub

参考

感想

エンドレスモナドチュートリアルが終わって新学期が来た感じ

ruby2.2.2で現在実行中の関数名を取得する

前提

ganmacs@ganmacs~% ruby -v
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]

内容

現在実行中の関数名を取得したいとき、ruby 1.8までは以下のようにしてとれた。   しかし1.9からto_s(Array)の挙動が変わったらしく2.2.2では動かなった。

class Object
  def current_method
    caller.first.scan(/`(.*)'/).to_s
  end
end

# when ruby version is 1.8 or earlier
puts current_method #=> "<main>"

# when ruby verison is 1.9 or later
puts current_method #=> [["<main>"]]

なので今は以下のように書くと実行中の関数名を取得できる

class Object
  def current_method_name
    caller.first.match(/`(?<method_name>.*)'/)[:method_name]
  end
end

puts current_method_name #=> "<main>"

参考

to_s (Array) - Rubyリファレンス

Rubyで今実行中のメソッド名を知る - 2nd life

正規表現