Hatena::ブログ(Diary)

Watsonのメモ RSSフィード

2012-03-07

MacRuby の Xcode 4.3 向けの対応

Xcode 4.3 のインストール場所が、これでは "/Deveroper" 以下のディレクトリだったのですが、Xcode 4.3 からは "/Applications" 以下になってしまいました。そのため、MacRuby 0.10 などすでにリリースしているパッケージでは、正しくインストール出来ない状態となっています。(対応は済んでいるので nightly build を使っていただけると Xcode 4.3 でも動くようになります)

MacRuby 道場というページを作り、環境構築方法やアプリケーションの作り方を書いてみました。

はてなダイアリーにいろいろ書いてきましたが、どうもまとまりがない感じで読みにくいので、今後は少しずつまとめながら気長に移行していけたらなと思っています。(ニュース的なものは今後もこちらに書くとは思います)

ということで、MacRuby 道場 をよろしくお願いします(^o^)/

2011-12-05

CocoaPods ではじめる Objective-C ライブラリ管理 (2)

2011 年の Mac Dev JP advent calendar 5 日目の記事です。CocoaPods ではじめる Objective-C ライブラリ管理 (1) の続きです。

CocoaPods はとても有益なツールだと思います。しかしながら、公式にサポートしているライブラリの種類が CocoaPods/Specs に登録されているものだけです。今日は、CocoaPods/Specs に登録されていないライブラリを CocoaPods で扱う方法について書きます。

登録されていないライブラリを扱うには 2 つ方法があります。

1. Podfile にライブラリ情報を記述する

昨日、Podfile を記述してライブラリをインストールする方法を書きました。その記事では CocoaPods に登録されいるライブラリを扱っているのみでした。Podfile には、どこからライブラリをダウンロードして、どのファイルをプロジェクトに追加するかを記述することができます。

執筆時点で CocoaPods/Specs に登録されていない、Chameleon というライブラリの UIKit を使ってみましょう。Podfile に以下のように記述します。

platform :osx

dependency do |spec|
  spec.source = { :git => 'https://github.com/BigZaphod/Chameleon.git' }
  spec.source_files = 'UIKit/Classes/*'
  spec.resources    = 'UIKit/Resources/*.png'
  spec.name = 'UIKit'
  spec.framework = 'IOKit', 'QuartzCore', 'SystemConfiguration', 'AppKit', 'Foundation', 'QTKit', 'WebKit'
end

GitHub の Chameleon レポジトリからソースを取得し、プロジェクトに UIKit/Classes/ 以下のファイルを追加します。Chameleon が依存する Framework を指定しています。記述できる内容については、2 つ目の方法と重複するので後ほど記載します。

ライブラリをインストールします。

$ pod install CocoaPodsSample.xcodeproj
Updating spec repo `master'
Using UIKit ()
Generating support files

1回きりしか Chameleon を使わないのであればこれでも良いかと思いますが、何度も使いたい場合には 2 つ目の方法を使用するとスマートかと思います。

ちなみに、想定外の使い方だったのか、コードを変更しないとリソース画像が表示されませんでした。。。

diff --git a/Pods/UIKit/UIKit/Classes/UIImage+UIPrivate.m b/Pods/UIKit/UIKit/Classes/UIImage+UIPrivate.m
index 3b292f4..bf2381a 100644
--- a/Pods/UIKit/UIKit/Classes/UIImage+UIPrivate.m
+++ b/Pods/UIKit/UIKit/Classes/UIImage+UIPrivate.m
@@ -108,7 +108,7 @@ NSMutableDictionary *imageCache = nil;
     UIImage *image = [self _cachedImageForName:name];
 
     if (!image) {
-        NSBundle *frameworkBundle = [NSBundle bundleWithIdentifier:@"org.chameleonproject.UIKit"];
+        NSBundle *frameworkBundle = [NSBundle mainBundle];
         NSString *frameworkFile = [[frameworkBundle resourcePath] stringByAppendingPathComponent:name];
         image = [[self imageWithContentsOfFile:frameworkFile] stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:topCapHeight];
         [self _cacheImage:image forName:name];

2. PodSpec を記述し、ライブラリ情報を定義する

2つ目の方法として、CocoaPods/Specs のようにライブラリ情報が書かれたファイルを用意します。

Terminal.app で 'pod spec create' コマンドを実行すると、PodSpec ファイルのひな形ができます。

$ pod spec create UIKit
$ ls  
UIKit.podspec

「UIKit.podspec」というファイルができます。このファイルに書かれたコメントを読みながら、必要な情報を書きこんでいきます。(ちゃんとしたドキュメントがまだ用意されていないようです)

Pod::Spec.new do |s|
  s.name     = 'UIKit'
  s.version  = '0.0.0'
  s.license  = 'BSD'
  s.summary  = "Chameleon is a port of Apple's UIKit (and some minimal related frameworks) to Mac OS X."
  s.homepage = 'https://github.com/BigZaphod/Chameleon'
  s.author   = 'Sean Heber'

  s.source   = { :git => 'https://github.com/BigZaphod/Chameleon.git' }
  s.platform = :osx

  s.source_files = 'UIKit/Classes/*'
  s.resources = "UIKit/Resources/*.png"

  s.frameworks = 'IOKit', 'QuartzCore', 'SystemConfiguration', 'AppKit', 'Foundation', 'QTKit', 'WebKit'
end

PodSpec で記述する各項目について以下で説明します。1 つ目の Podfile で記述した内容も同じです。

属性内容
name ライブラリの名称
version ライブラリのバージョン
license ライブラリに適用されているライセンスを記入します。(MIT、BSD、GPL2など)
summary ライブラリの簡単な説明を記入します。
homepage ライブラリが公開されている URL を記入します。
author 著作者の情報を記入します。

s.author = { 'Watson' => 'watson1978@gmail.com' }

メールアドレスを公開しない場合には、

s.author = 'Watson'

で良いようです。

source ソースコードを入手するためのリポジトリ URL を記入します。

s.source = { :git => 'https://github.com/BigZaphod/Chameleon.git’ }

特定の TAG を取得する場合には、

s.source = { :git => 'https://github.com/BigZaphod/Chameleon.git’ , :tag => 'xxxx' }

特定のコミットを取得する場合には、

s.source = { :git => 'https://github.com/BigZaphod/Chameleon.git’ , :commit => 'xxxx' }

SubversionMercurial レポジトリから取得する場合には、

s.source = { :svn => 'http://EXAMPLE/test/tags/1.0.0’ }

s.source = { :hg => 'http://EXAMPLE/test’, :revision => '1.0.0' }

と記述します。

source_files ライブラリで実際に使用するソースファイルを指定します。

'UIKit/Classes/' 以下の *.m と *.h を使用する場合には、

s.source_files = 'UIKit/Classes/*.m', 'UIKit/Classes/*.h'

のようになります。

ここまでは(たぶん)必須の設定項目になります。以下はオプションの設定項目です。

属性内容
platform 依存するプラットフォームを記入します。iOS でしか動作しないものであれば、:iosMac OS X のみでれば :osxと記入します。どちらのプラットフォームでも動作するライブラリの場合には未記入とします。
resourceresources 使用するリソースファイルを指定します。

リソースファイルが 1 つのみであれば、

s.resource = "icon.png"

複数のリソースファイルを扱う場合には、

s.resources = "Resources/*.png"

と記述します。

clean_pathclean_paths ライブラリで不要なファイルを指定します。例えば、Examples や doc など不要であれば、clean_path で指定することで、pod install コマンド実行時にファイルが削除されるようになります。

s.clean_path = "examples"

s.clean_paths = "examples", "doc"

frameworkframeworks 依存する Framework を指定します。

s.framework = 'SomeFramework'

s.frameworks = 'SomeFramework', 'AnotherFramework'

librarylibraries 依存する library を指定します。

s.library = 'iconv'

s.libraries = 'iconv', 'xml2'

requires_arc ライブラリが ARC を必要とするかを指定します。ARC が必要な場合には、

s.requires_arc = true

と記述します。

xcconfig ビルド設定を追加する必要がある場合に使用します。

s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2' }

dependency CocoaPods で扱えるライブラリに依存している場合に使用します。

s.dependency 'JSONKit', '~> 1.4'

記述した PodSpec ファイルに誤りがないか、'pod spec lint' コマンドで確認できます。

$ pod spec lint UIKit.podspec

もし記述に誤りがあればエラーが表示されるので、エラーが無くなるまで修正します。

できあがった、UIKit.podspec ファイルを以下のように "ライブラリ名/バージョン番号/ライブラリ名.podspec" という階層構造で保存します。

f:id:Watson:20111203224510p:image

これを GitHub にプッシュすれば、CocoaPods/Specs と同じようなディレクトリ構成になっているかと思います。最後に、'pod repo add' コマンドでレポジトリに追加すると、自分専用のライブラリ定義を使えるようになります。

$ pod repo add my_pods git://github.com/Watson1978/podspec.git
Cloning spec repo `my_pods' from `git://github.com/Watson1978/podspec.git'

git://github.com/Watson1978/podspec.git は私が作ったレポジトリです。~/.cocoapods にレポジトリが追加されます。

$ cd ~/.cocoapods/; ls
master/  my_pods/

これで UIKit を使うときには、

platform :osx
dependency 'UIKit'

と Podfile に記述するだけとなります。

定義したライブラリ情報を複数の方や、複数プロジェクトで使用したり、または CocoaPods に pull request することができるでしょう。


以上、長くなりましたが 2 日にわたり CocoaPods の使い方について書きました。CocoaPods はまだできたばかりのプロジェクトなので、日々新しくなり、ここに書いた内容が古くなると思います。公式サイトの情報もご確認ください。そして、不具合を見つけた場合には、@CocoaPodsOrg 宛につぶやくか、GitHub の issue に報告してください。

Enjoy! :)

2011-12-04

CocoaPods ではじめる Objective-C ライブラリ管理 (1)

2011 年の Mac Dev JP advent calendar 4 日目の記事です。今日、明日の 2 回に分けて CocoaPods について説明します。

CocoaPods とは?

CocoaPods とは、Mac アプリや iOS アプリ開発者向けに作られたライブラリ管理ツールです。MacRuby コミッターでもある Eloy Durán さんによってプロジェクトが開始されました。

今までは作成するアプリに適合するライブラリを Google などで検索し、ダウンロードした後に手作業でプロジェクトへソースファイルを追加する必要がありました。CocoaPods を使うと、これらの作業がいくつかのコマンドで完了することができます。

1. MacRuby のインストール

CocoaPods は、あらかじめ MacRuby 0.10 以降がインストールされている必要があります。MacRuby 0.10 をダウンロードしてインストールしておきます。

最近の CocoaPods は OSX 標準の ruby でも動作するようになっていますので、MacRuby はインストールしなくても良いです。その場合、macgem のかわりに gem コマンドを利用して CocoaPods をインストールしてください。

2. CocoaPods のインストール

CocoaPods は RubyGems の一つとして提供され、macgem コマンドを使用して CocoaPods をインストールできます。macgem コマンドは MacRuby をインストールすると使えるようになります。

Terminal.app で以下のようにコマンドを実行しましょう。

$ sudo macgem install cocoapods
[!] If this is your first time install of CocoaPods, or if you are upgrading, first run: $ pod setup
Successfully installed xcodeproj-0.0.2
Successfully installed cocoapods-0.3.9
2 gems installed

CocoaPods で扱えるライブラリの情報をセットアップします。

$ pod setup
Updating spec repo `master'

上記のコマンドを実行すると、~/.cocoapods ディレクトリに CocoaPods/Specs のファイルがミラーリングされます。CocoaPods は ~/.cocoapods ディレクトリのファイルを利用してライブラリ管理を行います。

~/.cocoapods を更新する場合は、再度 pod setup コマンドを実行します。

pod --help と実行すると、pod コマンドのヘルプを参照できます。

$ pod --help
To see help for the available commands run:

  * $ pod setup --help
  * $ pod search --help
  * $ pod install --help
  * $ pod repo --help
  * $ pod spec --help

Options
-------

    --help      Show help information
    --silent    Print nothing
    --verbose   Print more information while working
    --version   Prints the version of CocoaPods

3. Xcode プロジェクトを用意

CocoaPods を利用する、Xcode プロジェクトを用意しておきます。ここでは、「CocoaPodsSample」という名前で、Mac アプリのプロジェクトを用意します。(CocoaPods は iOS アプリのプロジェクトでも利用できます)

4. Podfile を作成

AFNetworking というライブラリをインストールしてみます。さきほど作成した CocoaPodsSample プロジェクトの CocoaPodsSample.xcodeproj と同じディレクトリに「Podfile」というファイルを、以下の内容を記述し用意します。

platform :osx
dependency 'AFNetworking'

f:id:Watson:20111203000532p:image

CocoaPods/Specs に登録されているライブラリを CocoaPods で扱うことができます。


Podfile には以下のような内容を記述できます。

属性内容
platform プラットフォームを指定します。

  • :ios
    iOS アプリを作成する場合に指定します。
  • :osx
    Mac OS X アプリを作成する場合に指定します

dependency プロジェクトで使用するライブラリを指定します。ライブラリ名とバージョン番号を指定できます(バージョン番号はオプション)

例) dependency 'Objection', '0.9'

バージョンの指定方法

'0.1' バージョン 0.1 を使用
'> 0.1' 0.1 より上のバージョンを使用
'>= 0.1' 0.1 以上のバージョンを使用
'< 0.1' 0.1 未満のバージョンを使用
'<= 0.1' 0.1 以下のバージョンを使用
'~> 0.1.2' 0.1.2 以降の 0.1.x バージョンを使用

generate_bridge_support! MacRuby や Nu、JSCocoa 向けに BridgeSupport を作成する場合に指定します。

Podfile に記述できる内容の一部を上記表に記載しました。より詳細について知りたい方は rubydoc.info/gems/cocoapods/Pod/Podfile を参照してください。

5. ライブラリをインストール

最後にTerminal.app で Podfile を保存したディレクトリで以下のようにコマンドを実行します。

$ pod install CocoaPodsSample.xcodeproj 
Updating spec repo `master'
Installing AFNetworking (0.7.0)
Installing JSONKit (1.4)
Generating support files
[!] From now on use `CocoaPodsSample.xcworkspace' instead of `CocoaPodsSample.xcodeproj'.

コマンドを実行すると「Pods」というディレクトリと、「CocoaPodsSample.xcworkspace」というファイルが作成されます。

f:id:Watson:20111203000533p:image

Pods ディレクトリには AFNetworking ライブラリに関するファイルと、この AFNetworking が依存するライブラリがインストールされます。Xcode で CocoaPodsSample.xcworkspace を開くと、ライブラリがセットアップされた状態になっています。

f:id:Watson:20111203000534p:image

新規プロジェクトを作成するたびに、「4. Podfile を作成」と「5. ライブラリをインストール」を行うことで、いままでよりも簡単にライブラリを導入することができるかと思います。


4'. PodCreator で Podfile を作成

手作業で Podfile を作成していると、私はどうしても記述ミスをしてしまったりしてしまうので、「PodCreator」というアプリケーションを MacRuby で作成しました。このアプリケーションを使うと、簡単な操作で Podfile を作れます。CocoaPods を使用する際に MacRuby をインストールされているはずなので、すぐに動かすことができるかと思います。

アプリケーションを実行すると以下のような画面が表示されます。

f:id:Watson:20111203002703p:image

1. platform を選択します。

2. "+" をクリックします。

f:id:Watson:20111203002704p:image

3. ライブラリの一覧が表示されるので、使用するものをダブルクリックし追加します。

f:id:Watson:20111203002705p:image

4. [Create Podfile]をクリックすると保存先をきかれますので、Podfile を保存するディレクトリを指定してください。


明日は PodSpec ファイルを記述して、CocoaPods に登録されていない自作のライブラリなどを扱う方法について書きたいと思います。

CocoaPods ではじめる Objective-C ライブラリ管理 (2) へつづく。


Enjoy CococaPods! :)

2011-10-31

TokyuRubyKaigi04 で MacRuby 本の宣伝をしてきました。

ただいま、Ruby 初心者のかたを対象に、MacRuby でアプリを作って Mac App Store で販売する方法を記載した本を id:kouji0625 さんと数名で絶賛執筆中です。TokyuRubyKaigi04でその本について宣伝してきました。

発表時間は 5 分かと思っていたのですが、会場についてパンフレットを見ていて 3 分しかないことに気づき、もう一つ用意していた例を削除して時間調整しました orz

いろいろな方とお話ができて、楽しかったです。

2011-10-02

MacRuby でサービスメニューに対応したアプリを作る

お久しぶりです。今日は朝からサービスメニューと格闘しておりました。みなさんはサービスを使っていますか?メニューをたどるとありますよね。

f:id:Watson:20111002122418p:image

さっそく作って行きましょう。

info.plistを編集

プロジェクトを作成したら、"プロジェクト名-info.plist" を開いて以下のように「Services」の内容を追加します。

f:id:Watson:20111002123030p:image

"info.plist"をエディタで直接編集する場合には、以下の記述を追加します。

	<key>NSMainNibFile</key>
	<string>MainMenu</string>
	<key>NSPrincipalClass</key>
	<string>NSApplication</string>
---- 次の行から
	<key>NSServices</key>
	<array>
		<dict>
			<key>NSMessage</key>
			<string>doService</string>
			<key>NSPortName</key>
			<string>Service</string>
			<key>NSSendTypes</key>
			<array>
				<string>NSStringPboardType</string>
			</array>
			<key>NSMenuItem</key>
			<dict>
				<key>default</key>
				<string>MacRuby Service Test</string>
			</dict>
		</dict>
	</array>
---- 上の行までを追加する
</dict>
</plist>

今回追加したのは、以下の4つの情報。

  • NSMessage (Instance method name)

サービスが実行されると、呼び出されるメソッド名を記述

  • NSPortName (Incoming service port name)

サービスを処理するアプリケーション名

  • NSSendTypes (Send Types)

サービスに対応するデータの種類

  • NSMenuItem (Menu)

サービスメニューに表示するメニュー名

サービスの処理を行ったあとで、サービスを呼び出したアプリケーションにデータを返したりする場合にはもう少し記述を追加する必要があるみたいです。

サービスを処理するメソッドを実装

info.plist の NSMessage で追加したメソッドを実装します。メソッドは以下の形式で定義します。

def doService(pboard, userData:userData, error:error)

定義したメソッドで、サービスの処理内容を実装します。

サービスにアプリケーションを登録

アプリケーション起動時にサービスへ登録しないといけないようなので、NSApp.setServicesProvider(self) というコードを applicationDidFinishLaunching に追加します。

def applicationDidFinishLaunching(a_notification)
  NSApp.setServicesProvider(self)
end

実行

実装が完了したら、ビルドしたアプリをアプリケーションフォルダか ~/Library/Services にコピーします。サービスメニューを更新するために再ログインします。

次にシステム環境設定でサービスを有効にします。

f:id:Watson:20111002130301p:image

今回のアプリケーションでは NSStringPboardType に対応しているので、他のアプリケーションで文字列を選択した状態でサービスを呼び出すと、選択範囲の文字列が渡されます。

最終的に実装したものは以下のようになりました。サービスで渡された文字列を Google Translate API で英語から日本語に翻訳して表示します。

# Google Translate API key
API_KEY = 'AIzaSyDNLefOLDCAlDm5niZP_2LX7RIEdmnPwbM'

require 'json'
require 'uri'
require 'open-uri'

class AppDelegate
  attr_accessor :window
  attr_accessor :text # Text View Outlet

  def applicationDidFinishLaunching(a_notification)
    NSApp.setServicesProvider(self)
  end

  def doService(pboard, userData:userData, error:error)
    window.makeKeyAndOrderFront(nil)
    string = pboard.stringForType(NSStringPboardType)

    translate(string)
  end

  def translate(string)
    source = 'en'
    target = 'ja'
    
    if string.length > 0
      open(URI.escape("https://www.googleapis.com/language/translate/v2?key=#{API_KEY}&source=#{source}&target=#{target}&q=#{string}")) {|f|
        str = f.read
        js = JSON.parse(str)
        text.setString(js['data']['translations'][0]['translatedText'])
      }
    end
  end
end

f:id:Watson:20111002130826p:image

ソースコード

から取得できます。

参考にしたサイトは、

です。

それでは、みなさんおもしろいサービスを作ってみてください!(^o^)/

Connection: close