Author Archive

    はてなブックマーク - ファイル・ディレクトリ名コレクション
    このエントリーをはてなブックマークに追加

    Fusic 中野です。
    暑い中昼休みにゲームソフトを買いに行ったら、来週発売でした。

    ちょっとした小ネタ。

    弊社は主にRubyかPHPでプログラムを書くことが多い会社なので、今回はGo言語とHaskellについて
    書いてみようかと思います。

    Haskell製の自作ツールをGo言語で書き直していたのですが、あるディレクトリ配下のファイル一覧を
    取得する処理を簡単に記述できたので、ちょっと比較をしてみようかと思います。

    Go言語(MacOSX go1.3 darwin/amd64)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    package main
    import (
    	"fmt"
    	"os"
    	"path/filepath"
    )
     
    func main() {
    	var result []string = make([]string, 0) // グローバルはいや!
    	walk := func (p string, info os.FileInfo, _ error) error {
    		if info.IsDir() {
    			result = append(result, "Directory: " + p)
    		} else {
    			result = append(result, "File: " + p)
    		}
    		return nil
    	}
    	filepath.Walk(".", walk)
    	fmt.Println(result)
    }

    Haskell(MacOSX ghc version 7.6.3)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    module Main where
     
    import Control.Monad.Writer
    import Control.Monad.State
    import System.FilePath
    import System.Directory
     
     
    main :: IO ()
    main = go "." >>= print
        where
            go p = execWriterT $ runStateT walk [p] -- go :: FilePath -> IO [FilePath]
            walk = do -- walk :: StateT [FilePath] (WriterT [FilePath] IO) ()
                p <- get
                case p of
                    (x:xs) -> do
                        d <- lift . lift $ doesDirectoryExist x
                        if d then do
                            files <- lift . lift $ getDirectoryContents x
                            put $ xs ++ [x </> f | f <- files, f /= "." && f /= ".." ]
                            tell ["Directory: " ++ x]
                            else do
                                put xs
                                tell ["File: " ++ x]
                        walk
                    _  -> return ()

    たぶん、似たようなことをしているかと思います。

    まとめ

    今日はGo言語が1.3がリリースされました。もう、心がぴょんぴょんしてきます。

    また、もっと簡単にかけるぜ!という方、もしくは、PHPやRubyなどに興味があり、
    Fusicで一緒に働いてみたいという方はこちら
    フォームからご応募くださいませ。

    それでは。

    { 2013.12.6 }

    すごいHなテスト

      はてなブックマーク - すごいHなテスト
      このエントリーをはてなブックマークに追加

      福岡事務所に電話をしたら、「どなたですか?」と聞かれた中野@東京事務所です。

      テストコードを書くのが苦手です。ついつい、手抜きを考えてしまいます。
      何が面倒かというと、やはり、テスト用のデータを作成することがめんどいです。

      ということで、そんなあなたにお勧めのHaskellです。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      
      {-# LANGUAGE GeneralizedNewtypeDeriving #-}
      -- hoge.hs
       
      import Test.QuickCheck
      import Test.QuickCheck.Monadic
       
      import Control.Applicative
      import Control.Monad.State
      import Control.Monad.Writer
       
      data Q = Q Int deriving Show
      data S = S { fstS :: String, sndS :: String } deriving Show
      data W = W { getQ :: Q,  getS :: S } deriving Show
       
      instance Arbitrary S where
        arbitrary = S <$> elements ["Mr.", "Ms.", "Mrs."] <*> elements ["Hoge", "Foo", "Bar", "Hage"]
       
      newtype AppT w m a = AppT { runQ :: StateT W (WriterT w m) a }
          deriving (Monad, MonadIO, MonadState W, MonadWriter w)
       
      exec :: AppT [String] IO Int
      exec = do
        w <- get
        let Q(q) = getQ w
            s = getS w
            name str = fstS str ++ " " ++ sndS str
        tell ["No." ++ show q]
        tell [name s]
        return q
       
      main' :: S -> Int -> IO [String]
      main' s a = main'' (W (Q a) s)
        where
          main'' w = do
            (_, r) <- runWriterT $ runStateT (runQ exec) w
            return r
       
      prop_main' :: S -> Int -> Property
      prop_main' s a = (a < 100 && a > 0) ==> monadicIO $ do
        res <- run $ main' s a
        assert $ res == ["No." ++ show a, fstS s ++ " " ++ sndS s]
       
      main :: IO ()
      main = quickCheck prop_main'
       
      -- $ runghc hoge.hs

      OH, さすがすごいHな言語。自動でテストのデータを作成してくれました。
      (ScalaにもScalaCheckという似たようなやつがあります)

      まとめ

      まあ、ランダムな値なので確実とはいいませんが、簡単にできるので重宝しております。
      弊社ではよくPHPやRubyなどの動的型付言語をやってるみたいですが、型推論がある関数型言語はいろいろと手抜きができて便利です。

      テストを書くのに疲れたから、さぼってたわけではありません。暁ちゃんかわいい。

      { 2013.7.29 }

      LambdaとTryと私

        はてなブックマーク - LambdaとTryと私
        このエントリーをはてなブックマークに追加

        こんにちは、Fusicの中野です。
        Ruby on Rails(ActiveSupport) にObject#tryという便利なメソッドがあります。

        1
        2
        3
        4
        5
        
        a = { b: 1}
        a.try(:[], :b) # => 1
         
        a = nil
        a.try(:[], :b) # => nil

        で、便利なのでついついこんな感じで書いてしまいます。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        
        class Tables < ActiveRecord::Migration
          def up 
            create_table :as do |t|
              t.text :title
              t.timestamps
            end
            create_table :bs do |t|
              t.text :title
              t.integer :a_id
              t.timestamps
            end
            create_table :cs do |t|
              t.text :title
              t.integer :b_id
              t.timestamps
            end
            a = A.new(title: "title")
            a.bs << B.new(title: "title1-1"); a.bs << B.new(title: "title1-2")
            a.bs[0].cs << C.new(title: "title1-1-1"); a.bs[0].cs << C.new(title: "title1-1-2"); a.bs[0].cs << C.new(title: "title1-1-3")
            a.bs[1].cs << C.new(title: "title1-2-1")
            a.save
          end
          def down; drop_table :as; drop_table :bs; drop_table :cs; end
        end
         
        # ↑のようなデータがあったとして
         
        c = C.find_by_id(1)
        c.try(:b).try(:a).try(:title).try { |_| "#{_} == title" } # => "title == title"

        なんかかっこ悪いので、こちらの素敵なライブラリを使ってみましょう。

        1
        2
        3
        4
        5
        6
        7
        
        require &#039;lambda_driver&#039;
         
        c = C.find_by_id(1)
        (-:try < c).(&:b >> :a >> :title >> lambda { |_| "#{_} == title" }) # => "title == title"
         
        c = C.find_by_id(10)
        (-:try < c).(&:b >> :a >> :title >> lambda { |_| "#{_} == title" }) # => nil

        すごく、ナウいですね。

        最後に

        最近、このブログがPHPばかりだったので、なんとなくRubyの記事を載せてみました。
        決して社内研修の次の日なので、疲れているとかではありません。