Gemfile/Gemfile.lock/gemspec/Rakefileそれぞれの違い・役割
Gemfile
- gemの取得先を記述する
- 通常はsourceとgemspecの2行、もしくはsourceの1行だけでよい
source "https://rubygems.org" gemspec
gemspec
- 実際の情報を記述するファイル
Gem::Specification.new do |s| s.authors = [] s.homepage = '' ・ ・ ・
- gemの依存関係をやgemの情報を記述するファイル
s.add_dependency '*****' s.add_development_dependency '***'
Rubyのpack, unpackでエンディアンを指定する方法
前回に引き続きエンディアン関連のポストです。
ネットワークバイトオーダー・ビッグエンディアン・リトルエンディアンとは - 脳汁portal
BOMをデータの先頭に付与することで、データを受け取る側がエンディアンを判別できるようになると書きましたが、Rubyでは標準ライブラリでエンディアンの指定ができるのでその方法を書きます
コマンド
基本形
Array.pack(format) String.unpack(format)
- pack時のdataはarrayで指定する
- unpack時のdataはStringで指定する
- formatは以下参照
ビッグエンディアン
array.pack("N*") string.unpack("N*")
- Nの数はarrayのサイズ
- *で無制限
- 足りない場合はエラーになる
- arrayの数の方が少ない場合は無視される
例
ビッグエンディアン
$ irb 2.1.2 :001 > [1].pack("N") => "\x00\x00\x00\x01" 2.1.2 :002 > [1,2].pack("NN") => "\x00\x00\x00\x01\x00\x00\x00\x02" 2.1.2 :003 > "\x00\x00\x00\x01\x00\x00\x00\x02".unpack("NN") => [1, 2]
リトルエンディアン
$ irb 2.1.2 :001 > [1].pack("V") => "\x01\x00\x00\x00" 2.1.2 :002 > [1,2].pack("V*") => "\x01\x00\x00\x00\x02\x00\x00\x00" 2.1.2 :003 > "\x01\x00\x00\x00\x02\x00\x00\x00".unpack("VV") => [1, 2] # ちなみにformatを間違えると・・・ 2.1.2 :004 > "\x01\x00\x00\x00\x02\x00\x00\x00".unpack("NN") => [16777216, 33554432] ### 正しい値がとれません
文字列で返ってきたHashやArrayをそれぞれのクラスに再変換する'to_array'と'to_h'メソッド
APIやTCP socketsの返り値が強制的にstringになってしまう場合に、それを再び正しいクラスへ戻すメソッドです。
to_array
to_array gem
install 方法
gem install to_array
例
require 'to_array' array = ['foo', 'bar', 'hoge', 'fuga'] str = array.to_s p str # => "[\"foo\", \"bar\", \"hoge\", \"fuga\"]" p str.class # => String p str.size # => 30 re_converted = str.to_array p re_converted # => ["foo", "bar", "hoge", "fuga"] p re_converted.class # => Array p re_converted.size # => 4
to_h
str_to_hash gem
install 方法
gem install str_to_hash
例
require 'str_to_hash' hash = {'foo'=>'bar', 'hoge'=>'fuga'} str = hash.to_s p str # => "{\"foo\"=>\"bar\", \"hoge\"=>\"fuga\"}" p str.class # => String p str.size # => 30 re_converted = str.to_h p re_converted # => {"foo"=>"bar", "hoge"=>"fuga"} p re_converted.class # => Hash p re_converted.size # => 2
念のために・・・
一応既存のメソッドをoverwriteしちゃってないか確認
2.1.2 :001 > String.new.public_methods.include?(:to_array) => false 2.1.2 :002 > String.new.public_methods.include?(:to_h) => false 2.1.2 :003 > String.new.public_methods.size => 164 2.1.2 :004 > require 'str_to_hash' => true 2.1.2 :005 > require 'to_array' => true 2.1.2 :006 > String.new.public_methods.size => 166
OK!
gemファイルを作成して公開する方法
自作のgemを開発してrubygems.orgへ公開する方法です。
RubyGems.org | your community gem host
- 今回はto_arrayという名前のgemを作りたいと思います。
to_array
arrayがto_strメソッドによってstringに変換されてしまったり、文字列で返ってきた場合に文字列からArrayに変換する
実装
1. 開発環境準備
$ bundle gem to_array -t Creating gem 'to_array'... MIT License enabled in config create to_array/Gemfile create to_array/.gitignore create to_array/lib/to_array.rb create to_array/lib/to_array/version.rb create to_array/to_array.gemspec create to_array/Rakefile create to_array/README.md create to_array/bin/console create to_array/bin/setup create to_array/LICENSE.txt create to_array/.travis.yml create to_array/.rspec create to_array/spec/spec_helper.rb create to_array/spec/to_array_spec.rb
2. 実際の処理を実装する
- lib/to_array.rbへ実装します。
最初はこのようなファイル内容です。
require "to_array/version" module ToArray # Your code goes here... end
↓これをこのように変更しました
class String def to_array if self[0] != "[" || self[-1] != "]" raise ArgumentError.new("invalid value for `str_to_array': '#{self}'") end begin arr = self.chomp.gsub(/"|^\[|\]$/, '') arr = arr.split(/,[\s]*/) return arr rescue raise ArgumentError.new("invalid value for `str_to_array': '#{self}'") end end end
3. 実際の動きを確認する
rubyのファイルを作成してもいいですが、今回はirbで確認します。
$ irb ### 作成したruby ファイルをrequire 2.1.2 :001 > require_relative './lib/to_array' => true ### その後は実装したメソッドを確認する 2.1.2 :005 > str = ['foo', 'bar', 'fizz', 'bazz'].to_s => "[\"foo\", \"bar\", \"fizz\", \"bazz\"]" 2.1.2 :007 > str.class => String 2.1.2 :008 > str.size => 30 2.1.2 :009 > reconverted = str.to_array => ["foo", "bar", "fizz", "bazz"] 2.1.2 :011 > reconverted.class => Array 2.1.2 :012 > reconverted.size => 4
問題ないですね。
# テストの作成
- spec/to_array_spec.rb内にテスト内容を記述します
- テストライブラリはrspecです
今回は以下のようにしました
require 'spec_helper' describe ToArray do arr1 = ['foo', 'bar', 'fizz', 'bazz'] str1 = arr1.to_s context "success case" do it 'should send back ArrayClass' do expect(str1.to_array).to be_a_kind_of(Array) end it 'should array size is same' do expect(str1.to_array.size).to eq(arr1.size) end end context "failure case(Other Object)" do it 'nil' do expect{nil.to_array}.to raise_error(NoMethodError) end it 'boolean' do expect{true.to_array}.to raise_error(NoMethodError) end it 'Already Array' do expect{arr1.to_array}.to raise_error(NoMethodError) end it 'Interger' do expect{100.to_array}.to raise_error(NoMethodError) end it 'Hash' do expect{{'foo'=>'bar', 'fizz'=>'bazz'}.to_array}.to raise_error(NoMethodError) end end context "failure case(Other Object)" do it 'nil' do expect{nil.to_array}.to raise_error(NoMethodError) end it 'boolean' do expect{true.to_array}.to raise_error(NoMethodError) end it 'Already Array' do expect{arr1.to_array}.to raise_error(NoMethodError) end it 'Interger' do expect{100.to_array}.to raise_error(NoMethodError) end it 'Hash' do expect{{'foo'=>'bar', 'fizz'=>'bazz'}.to_array}.to raise_error(NoMethodError) end end end
実際に確認します
$ rspec ToArray success case should send back ArrayClass should array size is same failure case(Other Object) nil boolean Already Array Interger Hash failure case(Other Object) nil boolean Already Array Interger Hash Finished in 0.00638 seconds (files took 0.06421 seconds to load) 12 examples, 0 failures
ここまで出来れば大体OKです。
あとはリリースの準備をします
リリース準備
README.mdを作成する
- 既にテンプレートが作成されてありますが、こちらを編集して使い方やダウンロード方法等を記入しておきましょう。
- 記法はMARKDOWN記法です
version番号の設定(任意)
- lib/to_array/version.rbのversion番号を変更しましょう。
- 最初なら1.0.0とかでいいでしょう。
module ToArray VERSION = "1.0.0" end
githubにソースをuploadする(任意)
travisCIの設定(任意)
gemの情報を入力する
to_array.gemspecの中のTODOと書かれている部分を修正しましょう
$ grep -r 'TODO' to_array.gemspec spec.authors = ["TODO: Write your name"] spec.email = ["TODO: Write your email address"] spec.summary = %q{TODO: Write a short summary, because Rubygems requires one.} spec.description = %q{TODO: Write a longer description or delete this line.} spec.homepage = "TODO: Put your gem's website or public repo URL here." spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
リリース
確認
$ rake -T rake build # Build to_array-1.0.0.gem into the pkg directory rake install # Build and install to_array-1.0.0.gem into system gems rake install:local # Build and install to_array-1.0.0.gem into system gems without network access rake release # Create tag v1.0.0 and build and push to_array-1.0.0.gem to Rubygems rake spec # Run RSpec code examples $ rake install:local to_array 1.0.0 built to pkg/to_array-1.0.0.gem. to_array (1.0.0) installed. $ irb 2.1.2 :001 > require 'to_array' => true 2.1.2 :002 > ['foo', 'bar'].to_s.to_array.class => Array 2.1.2 :003 > ['foo', 'bar'].to_s.to_array.size => 2 $ rake spec ToArray success case should send back ArrayClass should array size is same failure case(Other Object) nil boolean Already Array Interger Hash failure case(Other Object) nil boolean Already Array Interger Hash Finished in 0.00833 seconds (files took 0.06756 seconds to load) 12 examples, 0 failures
問題なければupload
upload
$ gem push pkg/to_array-1.0.0.gem Enter your RubyGems.org credentials. Don't have an account yet? Create one at https://rubygems.org/sign_up Email: ****************** Password: Signed in. Pushing gem to https://rubygems.org... Successfully registered gem: to_array (1.0.0)
これで無事リリースすることが出来ました。
to_array | RubyGems.org | your community gem host
to_boolメソッドをgem化して公開しました。
以前以下のように文字列で返ってきた"true"や"false"をBooleanに変換するto_boolメソッドの実装方法を紹介しましたが、それをgem化して公開しました。portaltan.hatenablog.com
たが問題として、「to_bool」も「to_boolean」も「to_b」も全部既にgemの名前として使われていました。。
苦肉の策としてgem名は「to-bool」にしました。
Install方法
gem install to-bool Fetching: to-bool-1.2.0.gem (100%) Successfully installed to-bool-1.2.0 Parsing documentation for to-bool-1.2.0 Installing ri documentation for to-bool-1.2.0 Done installing documentation for to-bool after 0 seconds 1 gem installed gem list to-bool *** LOCAL GEMS *** to-bool (1.2.0)
使い方
test.rb
require 'to-bool' p 'true'.to_bool #=> true p 'true'.to_bool.class #=> TrueClass p 'false'.to_bool #=> false p 'false'.to_bool.class #=> FalseClass p true.to_bool #=> true p true.to_bool.class #=> TruelClass p false.to_bool #=> false p false.to_bool.class #=> FalseClass
NoMethodError
対応していないObjectの場合はNoMethodErrorを返すようにしています
require 'to-bool' [].to_bool #=>undefined method `to_bool' for []:Array (NoMethodError)
ArgumentError
文字列が'true'か'false'の場合はArgumentErrorを返すようにしています。
require 'to-bool' p 'foo'.to_bool #=>invalid value for `to_bool': 'foo' (ArgumentError) p 'truetrue'.to_bool #=>invalid value for `to_bool': 'truetrue' (ArgumentError) p ''.to_bool #=>invalid value for `to_bool': '' (ArgumentError)
rubyのデフォルトのUnit testの使い方
Rubyにデフォルトで入っているテストフレームワークのUnit testの使い方です。
ちなみに以前書きましたがrubyのデフォルトのテストフレームワークは各versionで中身が違います。portaltan.hatenablog.com
使い方
準備
unit.rb
require 'test/unit' class SampleTest < Test::Unit::TestCase end
1. まずはテストフレームワークを使用するために'test/unit'をrequireします
2. つぎにTest::Unit::TestCaseを継承したclassを作成します
- rubyではTest::Unit::TestCaseを継承することで自動でそのクラスはテスト実行ファイルになります
これで基本的な設定は完了です。現時点で実行すると以下のようになります。
$ ruby unit.rb Run options: # Running tests: Finished tests in 0.002284s, 0.0000 tests/s, 0.0000 assertions/s. 0 tests, 0 assertions, 0 failures, 0 errors, 0 skips ruby -v: ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
テストの作成
次に実際のテスト処理を書きます
require 'test/unit' class SampleTest < Test::Unit::TestCase def test_sample1 foo = '111' assert_equal('111', foo) end end
1. test_*という名前のメソッドを作成します。
- 上のほうでTest::Unit::TestCaseを継承したクラスは自動でテスト実行ファイルになると書きましたが、実際はその中のtest_*というメソッドが、自動で実行されるテストになります。
2. メソッド内でチェックメソッドを書きます。書式は以下です。
assert_equal(予想される値, 変数やメソッド等)
- assert_equalでは変数の値やメソッドの返り値が予想と一致することを確認します。
上記を実行すると・・・
$ ruby unit.rb Run options: # Running tests: Finished tests in 0.004152s, 240.8293 tests/s, 240.8293 assertions/s. 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips ruby -v: ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
- 先ほどは0だったtestsとassertionsが1件増えました。
予想とは違う場合は以下のようになります。
メソッド
def test_sample1 foo = '111' assert_equal('111', foo) end
実行結果
]$ ruby unit.rb Run options: # Running tests: [1/1] SampleTest#test_sample1 = 0.00 s 1) Failure: SampleTest#test_sample1 [unit.rb:17]: <"222"> expected but was <"111">. Finished tests in 0.003316s, 301.5818 tests/s, 301.5818 assertions/s. 1 tests, 1 assertions, 1 failures, 0 errors, 0 skips
- failuresが1件増えています。
テストの前処理・後処理
class SampleTest < Test::Unit::TestCase @@i = 0 def setup @@i += 1 puts "\r\nstart test #{@@i}========================================" end def teardown puts "\r\nfinish test #{@@i}========================================" end def test_sample1 assert_equal('111', foo) end def test_sample2 assert_equal('222', foo) end end
実行結果
$ ruby unit.rb Run options: # Running tests: [1/2] SampleTest#test_sample1 start test 1======================================== finish test 1======================================== [2/2] SampleTest#test_sample2 start test 2======================================== finish test 2======================================== = 0.00 s 1) Failure: SampleTest#test_sample2 [unit.rb:23]: <"222"> expected but was <"111">. Finished tests in 0.003935s, 508.2782 tests/s, 508.2782 assertions/s. 2 tests, 2 assertions, 1 failures, 0 errors, 0 skips ruby -v: ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
- テスト毎に前処理・後処理が実行されているのがわかります。
Rubyの特殊変数($@とか$`とか$数字とか・・・)
特殊変数
Rubyの組み込み変数の一部は、通常の変数としては使用できない特殊な名前を持っています。
例えば、 $' や $& あるいは $1, $2, $12345678901234567890 がそうです。
このように 「'$' + 特殊文字一文字」、または「'$' + 10進数字」という名前を持つ変数を特殊変数と呼びます。
また、 $-F や $-I のような変数もあります。 これらは Ruby の起動オプションと -F や -I などと対応しており、オプション変数と呼ばれます。
とのことです。
ちょこちょこ忘れて調べるので、自分用メモも兼ねて例と一緒にまとめておきたいと思います。
特殊変数一覧
正規表現関係
$', $&, &`
- $' : マッチした文字列より前の文字列
- $& : マッチした文字列
- &` : マッチした文字列より後ろの文字列
str = 'abcdefghijk' /efg/.match(str) puts $` # => abcd puts $& # => efg puts $' # => hijk
$~
- マッチしたMatchDataオブジェクトを表示する
str = 'abcdefghijk' /efg/.match(str) puts $~.class # => MatchData puts $~ # => efg puts $&.class # => String puts $& # => efg
ファイル・ライブラリ関係
$"
- requireしたライブラリの一覧を帰す
require_relative "lib_sample1" require_relative "lib_sample2" puts $" # => [ # "enumerator.so", # . # . # "/home/roma/lib_sample2.rb" # ]
$:
requireが検索するディレクトリ一覧を返す
puts $: # => [ # "/usr/local/rvm/rubies/ruby-2.1.2/lib/ruby/site_ruby/2.1.0", # . # . # "/usr/local/rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/x86_64-linux" # ]
$-I
- ロードパスの一覧を返す
p $-I # => [ # "/usr/local/rvm/rubies/ruby-2.1.2/lib/ruby/site_ruby/2.1.0", # . # . # "/usr/local/rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/x86_64-linux"] # ]
$0
- ファイル名を表示する
### ruby test.rbの時 puts $0 # => test.rb
例外関係
$@
- 例外のバックトレース
begin raise rescue puts $@ # => test.rb:2:in `<main>' end