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

mogenerator コマンドで 「skipping entity User (NSManagedObject) because it doesn't use a custom subclass.」が出た場合の対処法

iOS Swift

問題

mogenerator コマンドを叩いたら以下のようなエラーが発生。

$ mogenerator -m swift-ios-example/swift-ios-example.xcdatamodeld/swift-ios-example.xcdatamodel/ -O Models/ --template-var arc=true

skipping entity User (NSManagedObject) because it doesn't use a custom subclass.
skipping entity User (NSManagedObject) because it doesn't use a custom subclass.
0 machine files and 0 human files generated.

原因

クラス名を指定していなかった。

解決方法

クラス名を指定する。

f:id:kzy52:20150526093607p:plain

$ mogenerator -m swift-ios-example/swift-ios-example.xcdatamodeld/swift-ios-example.xcdatamodel/ -O Models/ --template-var arc=true --swift

1 machine files and 1 human files generated.

CentOS に Errbit をインストールする

gem Linux

環境

CentOS 6.6

必要なライブラリーをインストールする

$ sudo yum install -y git nginx nodejs

MongoDB のインストールと起動

# /etc/yum.repos.d/mongodb-org.repo

[mongodb-org]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/
gpgcheck=0
enabled=1
$ sudo yum install -y mongodb-org
$ sudo service mongod start
$ sudo chkconfig mongod on

Nginx の設定

# /etc/nginx/conf.d/errbit.conf

upstream errbit {
  server unix:/var/www/vhost/errbit/tmp/sockets/unicorn.sock;
}

server {
  listen *:80;
  server_name errbit.example.com;
  server_tokens off;
  root /var/www/vhost/errbit/public;

  location / {
    try_files $uri $uri/index.html $uri.html @errbit;
  }

  location ~ ^/(assets)/ {
    root /var/www/vhost/errbit/public;
    access_log off;
  }

  location @errbit {
    proxy_set_header    Host                $http_host;
    proxy_set_header    X-Real-IP           $remote_addr;
    proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
    proxy_pass http://errbit;
  }
}

Nginx の起動

$ sudo service nginx start

Errbit のインストール

$ sudo mkdir -p /var/www/vhost
$ cd /var/www/vhost
$ sudo git clone https://github.com/errbit/errbit.git
$ sudo chown op:op -R errbit/
$ cd errbit/
$ bundle install --path vendor/bundle
$ bundle exec rake errbit:bootstrap
$ bundle exec rake assets:precompile RAILS_ENV=production
$ cp config/unicorn.default.rb config/unicorn.rb

unicorn の設定

# config/unicorn.rb

worker_processes 3
timeout 30
preload_app true

app_path = '/var/www/vhost/errbit'
working_directory = app_path

listen  File.expand_path('tmp/sockets/unicorn.sock', app_path)
pid File.expand_path('tmp/pids/unicorn.pid', app_path)
stderr_path File.expand_path('log/unicorn.stderr.log', app_path)
stdout_path File.expand_path('log/unicorn.stdout.log', app_path)

before_fork do |server, worker|
  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

Errbit の起動

$ bundle exec unicorn -c config/unicorn.rb -E production -D

f:id:kzy52:20150514081049p:plain

参考ページ

errbit/errbit · GitHub

CentOS に Ruby をインストールする

Ruby Linux

環境

CentOS 6.6

rbenv

Ruby のバージョン管理ツール。

ruby-build

Rubyの各バージョンのインストールツール。
rbenv install コマンドが使用できるようになる。

rbenv-default-gems

Ruby をインストールするときに指定した gem を自動でインストールしてくれるツール。

依存パッケージをインストールする

$ sudo yum -y install openssl-devel readline-devel zlib-devel libcurl-devel

rbenv のインストール

$ sudo su -

# cd /usr/local
# git clone git://github.com/sstephenson/rbenv.git rbenv
# mkdir rbenv/shims rbenv/versions rbenv/plugins
# groupadd rbenv
# chgrp -R rbenv rbenv
# chmod -R g+rwxXs rbenv

ruby-build のインストール

# cd /usr/local/rbenv/plugins

# git clone git://github.com/sstephenson/ruby-build.git ruby-build
# chgrp -R rbenv ruby-build
# chmod -R g+rwxs ruby-build

rbenv-default-gems のインストール

# git clone git://github.com/sstephenson/rbenv-default-gems.git rbenv-default-gems
# chgrp -R rbenv rbenv-default-gems
# chmod -R g+rwxs rbenv-default-gems

環境変数の設定

# /etc/profile.d/rbenv.sh

export RBENV_ROOT="/usr/local/rbenv"
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

デフォルトでインストールする gem の指定

# /usr/local/rbenv/default-gems

bundler
rbenv-rehash

設定の反映

# source /etc/profile.d/rbenv.sh

インストール可能な Ruby のバージョン確認

$ rbenv install -l

1.8.6-p383
1.8.6-p420
...
2.2.1
2.2.2
2.3.0-dev
jruby-1.5.6
...

Ruby のインストール

ここでは 2.2.2 をインストールし、グローバルとして設定する。

# rbenv install 2.2.2
# rbenv global 2.2.2
# ruby -v
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]

Mac OS X に Ruby をインストールする

Mac Ruby

環境

Mac OS X 10.10.3

rbenv

Ruby のバージョン管理ツール。

ruby-build

Rubyの各バージョンのインストールツール。
rbenv install コマンドが使用できるようになる。

rbenv-gemset

gem のインストール先を管理するためのツール。
プロジェクト毎に gem のインストール先を切り替えることができる。
開発環境では vendor/bundle にインストールするよりこれ使う方が好き。

rbenv-default-gems

Ruby をインストールするときに指定した gem を自動でインストールしてくれるツール。

インストール

$ brew install rbenv ruby-build rbenv-gemset rbenv-default-gems

初期設定

# ~/.bash_profile or ~/.zshrc

if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi

デフォルトでインストールする gem の指定

# ~/.rbenv/default-gems

bundler
rbenv-rehash

インストール可能な Ruby のバージョン確認

$ rbenv install -l

1.8.6-p383
1.8.6-p420
...
2.2.1
2.2.2
2.3.0-dev
jruby-1.5.6
...

Ruby のインストール

ここでは 2.2.2 をインストールし、グローバルとして設定する。

$ rbenv install 2.2.2
$ rbenv global 2.2.2
$ ruby -v
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]

CentOS に MongoDB をインストールする

MongoDB Linux

環境

CentOS 6.6

MongoDB のインストール

# /etc/yum.repos.d/mongodb-org.repo

[mongodb-org]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/
gpgcheck=0
enabled=1
$ sudo yum install -y mongodb-org

バージョン 3.0 をインストールしたい場合は baseurl を以下のように指定する。

baseurl=http://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.0/x86_64/

MongoDB の操作

# 起動
$ sudo service mongod start

# 停止
$ sudo service mongod stop

# 再起動
$ sudo service mongod restart

# シェルの起動
$ mongo

自動起動設定

$ sudo chkconfig mongod on

設定ファイル

/etc/mongod.conf

ログ

/var/log/mongodb/mongod.log

参考ページ

Install MongoDB on Red Hat Enterprise or CentOS Linux — MongoDB Manual 3.0.3

MeCab インストール時に「./configure」でエラーが発生した場合の対処法

自然言語処理

問題

$ ./configure

...
checking if g++ supports template <class T> (required)... configure: WARNING: g++ template <class T> does not work

checking if g++ supports GCC native atomic operations (optional)... no
checking if g++ supports OSX native atomic operations (optional)... no
checking if g++ environment provides all required features... no
configure: error: Your compiler is not powerful enough to compile MeCab.         If it should be, see config.log for more information of why it failed.

解決方法

$ sudo yum install gcc-c++

これで無事インストールできました。

Swift と Rails で iOS アプリ開発

Swift iOS Rails

フロントエンドを Swift で、バックエンドを Rails でアプリを開発してみます。

Web API 側実装

grape という gem を使って Web API を作っていきます。
以下の記事も参考にしてみてください。

Grape で Web API 開発 - kzy52's blog
Grape::Entity の使い方 - kzy52's blog

Rails プロジェクト作成

$ mkdir api-demo;cd api-demo
$ echo api-demo > .rbenv-gemsets
$ rbenv local 2.2.0
$ gem install bundler
$ gem install rails
$ rails new . --skip-sprockets

データベース作成

$ rake db:create

ユーザテーブルの作成

$ rails g model User name:string email:string
$ rake db:migrate

API 基盤の実装

gem の追加

# Gemfile
...

gem 'grape'
gem 'grape-entity'
$ bundle install

ディレクトリの作成

$ mkdir -p app/apis/api/v1
$ mkdir -p app/apis/entity/v1

app/apiをオートロードに追加

# config/application.rb

module ApiDemo
  class Application < Rails::Application
    ...
    # 以下を追加
    config.paths.add File.join('app', 'apis'), glob: File.join('**', '*.rb')
    config.autoload_paths += Dir[Rails.root.join('app', 'apis', '*')]
  end
end

API のルーティング追加

# config/routes.rb

Rails.application.routes.draw do
  mount API::Base => '/'
end

ベースクラスの作成

# app/apis/api/base.rb

module API
  class Base < Grape::API
  end
end

API のルーティングを確認するタスクの追加

# lib/tasks/routes.rake

namespace :api do
  desc 'API Routes'
  task routes: :environment do
    API::Base.routes.each do |api|
      method = api.route_method.ljust(10)
      path = api.route_path.gsub(':version', api.route_version)
      puts "     #{method} #{path}"
    end
  end
end

「rake api:routes」でgrapeで定義した API のルーティングを確認できます。

APIの実装

# app/apis/api/v1/base.rb

module API
  module V1
    class Base < Grape::API
      format :json
      default_format :json

      prefix 'api'
      version 'v1', using: :path
    end
  end
end
# app/apis/api/base.rb

module API
  class Base < Grape::API
    # 以下を追加
    mount V1::Base
  end
end
# app/apis/entity/v1/users_entity.rb

module Entity
  module V1
    class UsersEntity < Grape::Entity
      expose :id, :name, :email
    end
  end
end
# app/apis/api/v1/users.rb

module API
  module V1
    class Users < Grape::API
      resource :users do
        get do
          present User.all, with: Entity::V1::UsersEntity
        end
      end
    end
  end
end
# app/apis/api/v1/base.rb

module API
  module V1
    class Base < Grape::API
      ...
      mount V1::Users
    end
  end
end

データを入れて curl コマンドで API を叩いてみると以下のように返ってくると思います。

$ curl http://localhost:3000/api/v1/users
[{"id":1,"name":"user1","email":"user1@example.com"},{"id":2,"name":"user2","email":"user2@example.com"},{"id":3,"name":"user3","email":"user3@example.com"},{"id":4,"name":"user4","email":"user4@example.com"},{"id":5,"name":"user5","email":"user5@example.com"}]%

アプリ側実装

テンプレートは Single View Application で言語は Swift を選択してプロジェクトを作成します。 ここでは APIDemo というプロジェクト名にします。
Xcode はいったん閉じてください。

プロジェクトに移動する

先ほど作成した Xcode のプロジェクトに移動します。

$ cd APIDemo

Alamofire のインストール

今回はWeb APIをコールするので Alamofire/Alamofire · GitHub というHTTP通信用ライブラリ を使用します。

CocoaPods のインストール

CocoaPods はiOSライブラリ管理ツールです。
インストールされていない場合はインストールしてください。

$ gem install cocoapods

Podfileの作成

$ pod init
$ vim Podfile
# Podfile

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '8.0'
use_frameworks!

target 'APIDemo' do
  pod 'Alamofire', '~> 1.1'
end

target 'APIDemoTests' do

end

ライブラリのインストール

$ pod install

プロジェクトを開く

$ open APIDemo.xcworkspace

UITableView を使う準備

UITableView はテーブル表示にしたい場合に使用します。
今回はユーザ一覧の表示に使います。

// ViewController.swift

import UIKit

// UITableViewを使用する際はUITableViewDataSourceプロトコルとUITableViewDelegateプロトコルを実装する必要がある
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    let cellId = "MyCell"

    // 今回はテーブル表示にしたいので UITableView を使う
    var tableView : UITableView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // 横幅、高さ、ステータスバーの高さを取得する
        let width: CGFloat! = self.view.bounds.width
        let height: CGFloat! = self.view.bounds.height
        let statusBarHeight: CGFloat! = UIApplication.sharedApplication().statusBarFrame.height
        
        self.tableView = UITableView(frame: CGRectMake(0, statusBarHeight, width, height - statusBarHeight))
        
        // デリゲートを指定する
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        
        // UITableViewにセルとして使うクラスを登録する
        self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellId)
        
        // Viewに追加する。
        self.view.addSubview(self.tableView!)
    }
    
    // セルの総数を返す(表示するテーブルの行数)
    // UITableViewDataSource を使う場合は 必須
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // とりあえずは適当に返しておく
        return 1
    }
    
    // 表示するセルを生成して返す
    // UITableViewDataSource を使う場合は 必須
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // UITableViewCellはテーブルの一つ一つのセルを管理するクラス。
        let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as UITableViewCell
        
        return cell
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

ユーザを保持するクラスの作成

  1. [APIDemo] を右クリック > [New Group] を選択しグループ名を 「Models」 します。
  2. [Models]を選択し[ユーティリティエリア] > [Identity and type]の フォルダアイコンをクリックする。
  3. [New Folder] をクリックし、ダイアログが表示されるので「Models」ディレクトリを作成します。
  4. [Choose] ボタンをクリックします。
  5. [Models]を右クリック > [New File...] > [iOS] > [Source] > [Swift File] を選択し [Next] ボタンをクリックします。
  6. ファイル名を「User.swift」にし3で作成した[Models]に保存します。
// Models/User.swift

import UIKit

struct User {
    var name: String, email: String
}

class UserDataManager: NSObject {
    var users: [User]

    // シングルトンにする
    // UserDataManager.sharedInstanceで常に同じインスタンスを取り出すことができる。
    class var sharedInstance : UserDataManager {
        struct Static {
            static let instance : UserDataManager = UserDataManager()
        }
        return Static.instance
    }

    override init() {
        self.users = []
    }

    // ユーザーの総数を返す。
    var size : Int {
        return self.users.count
    }

    // 配列のように[n]で要素を取得できるようにする。
    subscript(index: Int) -> User {
        return self.users[index]
    }

    func set(user: User) {
        self.users.append(user)
    }
}
// ViewController.swift

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    ...
    var tableView : UITableView?

    var users = UserDataManager.sharedInstance

    ...
    // セルの総数を返す(表示するテーブルの行数)
    // UITableViewDataSource を使う場合は必須
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.users.size
    }

    // 表示するセルを生成して返す
    // UITableViewDataSource を使う場合は必須
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // UITableViewCellはテーブルの一つ一つのセルを管理するクラス。
        let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as UITableViewCell
            
        // Cellに値を設定する.
        let user: User = self.users[indexPath.row] as User
        cell.textLabel?.text = user.email
            
        return cell
    }
    ...
}

Web API へのリクエスト

[APIDemo] を右クリック > [New File...] > [iOS] > [Source] > [Swift File]を選択し、[Next]ボタンをクリックします。

[APIDemo] 配下に 「Router.swift」という名前で保存します。

ここは Alamofire/Alamofire · GitHub を参考にしました。

// Router.swift

import Alamofire

enum Router: URLRequestConvertible {
    static let baseURLString = "http://localhost:3000"
    
    case GetUsers()
    
    var URLRequest: NSURLRequest {
        let (method: Alamofire.Method, path: String, parameters: [String: AnyObject]?) = {
            switch self {
            case .GetUsers: return (.GET, "/api/v1/users", nil)
            }
        }()
        
        let URL = NSURL(string: Router.baseURLString)!
        let URLRequest = NSURLRequest(URL: URL.URLByAppendingPathComponent(path))
        let encoding = Alamofire.ParameterEncoding.URL
        
        return encoding.encode(URLRequest, parameters: parameters).0
    }
}
// ViewController.swift

import Alamofire

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    ...

    override func viewWillAppear(animated: Bool) {
        self.request()
    }

    // Web API をコールする
    func request() {
        Alamofire.request(Router.GetUsers()).responseJSON { (request, response, json, error) -> Void in
            if let json = json as? Array<Dictionary<String,AnyObject>> {
                for j in json {
                    var user: User = User(
                        name: j["name"] as NSString,
                        email: j["email"] as NSString
                    )
                    self.users.set(user)
                }
                
                dispatch_async(dispatch_get_main_queue(), {
                    self.tableView!.reloadData()
                })
            }
        }
    }
    ...

f:id:kzy52:20150325215141p:plain

ソースコード

github.com

参考ページ

Alamofire/Alamofire · GitHub