はじめに
iOSアプリ開発をしているとたまにちょっとしたスクリプト作りたいなぁと思うことがあります。今やってるプロジェクトも Ruby で書かれたスクリプトがあるのですが Ruby 読めないのでちょっとした修正もできない!!ってことでスクリプトの修正やちょっとしたスクリプトなら Ruby で書けるようになるための Ruby 入門を書きたいと思います。
今回の目標は ios-snapshot-test-case で作成したスクショ一覧をいい感じに Markdown で出力することです!
ios-snapshot-test-case については下記参考
Rubyの公式ドキュメントがパッとどれかわからなかったけどたぶんこれっぽい
環境構築
Mac には最初から Ruby が入っているのでこのままでもいいのですがせっかくなのでプロジェクトごとに環境を切り替えれるように設定します。
とりあえず rbenv を Homebrew でインストールします。
1 |
$ brew install rbenv ruby-build |
後は下記のような感じで任意のバージョンの Ruby をインストールします。(ruby -v
で任意のバージョンになっていればOK)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 1. インストール可能な ruby バージョンを調べる $ rbenv install -l // 2. 指定のバージョンの ruby をインストール $ rbenv install <バージョン> // 3. 使用する ruby バージョンを指定(.ruby-version ができるはず) $ rbenv local <バージョン> // 4. .zprofileに「eval "$(rbenv init -)"」追記 // 5.インストールした ruby を使用可能な状態にする $ rbenv rehash // 6. ターミナル再起動(.zprofile のやつ反映するため) // 7. ruby のパス(/.rbenv/shims/rubyになっていれば成功) $ which ruby |
今回は使いませんが gem を使うなら bundler も入れといた方がいいです。(gem はたぶんパッケージ管理ツールかつライブラリ自体を指すっぽい)
詳細は下記参考
MacにHomeBrew,rbenv,bundlerをインストールする
Ruby文法
環境構築ができたところで Ruby の基本的な書き方についてです。rbenv install --list
を実行すると 2.7.1 が一番新しそうなのでこれを使おうと思います。ドキュメントはたぶんこれ👇
https://docs.ruby-lang.org/ja/2.7.0/doc/index.html
変数と定数
Ruby の変数と定数の種別は変数名の最初の一文字によって、ローカル変数、インスタンス変数、クラス変数、グローバル変数、定数のいずれかに区別されるらしい。
種類 | 宣言 | 説明 |
---|---|---|
ローカル変数 | foo = "piyo" | 小文字または _ で始まる |
インスタンス変数 | @foo = "piyo" | @ で始まる |
クラス変数 | @@foo = "piyo" | @@ で始まる |
グローバル変数 | $foo = "piyo" | $ で始まる |
定数 | FOO = "piyo" | アルファベット大文字で始まる |
データ型
データ型は下記のようなものがあります。
データ型 | 説明 | 例 |
---|---|---|
Integer | 整数 | hoge = 2 |
Float | 小数 | hoge = 3.14 |
Array | 配列 | hoge = ["value1", "value2"] |
Hash | 連想配列 | { "key1" => "value1", "key2" => "value2" } |
FalseClass | false | hoge = false |
TrueClass | true | hoge = true |
NilClass | nil | hoge = nil |
演算子
算術演算子
- +
- -
- *
- /
- **(べき乗)
- %(余り)
比較演算子
- ==(左辺と右辺が等しい)
- !=(左辺と右辺が異なる)
- <
- >
- <=
- >=
- <=>
左辺 < 右辺 であれば -1、左辺 == 右辺 であれば 0、左辺 > 右辺 であれば 1、比較できない時は nil を返す - ===
self === obj
の場合、指定された obj が self かそのサブクラスのインスタンスであるとき真を返す
<=> 以外はすんなり使えそう
論理演算子
- and ( && )
- or ( || )
- not ( ! )
構文
条件分岐
if
1 2 3 4 5 6 7 8 |
num = 0 if num > 0 then print "Big\n" elsif num = 0 then print "Zero\n" else print "Small" end |
unless
if
の反対
1 2 3 4 5 6 |
num = 0 unless num > 0 then print "Zero or Small\n" else print "Big\n" end |
unless
はじめてみた。便利かも。
case
switchみたいなやつ
1 2 3 4 5 6 7 8 9 |
num = 0 case num when 0 print "Zero\n" when 1 print "One\n" else print "Other\n" end |
繰り返し
while
1 2 3 4 5 |
num = 0 while num < 10 do print num #0~9出力 num += 1 end |
until
1 2 3 4 5 |
num = 0 until num > 10 do print num #0~10出力 num += 1 end |
for
1 2 3 |
for num in 1..10 do print num #1~10出力 end |
処理抜け
for 文とかを途中で抜けるやつ
1 2 3 4 5 6 7 8 9 |
for num in 1..10 do if num % 2 == 0 then next end if num == 5 then break end print num #13出力 end |
他にも下記がある
- redo
- retry
- raise
- begin
- return
- BEGIN
- END
メソッド
メソッドの書式は下記
1 2 3 4 |
def メソッド名(引数1, 引数2, ...) 実行する処理 return 戻り値 #処理が一行ならreturnなくてもいい end |
例
1 2 3 4 5 6 7 |
def hoge(value1, value2 = 3) piyo = 5 * value1 return piyo + value2 end puts hoge(2) # 13 puts hoge(2, 5) # 15 |
慣習的にメソッド名は lower snake case で記載し真偽値を返すメソッドは ~? 、 破壊的なメソッドは ~! とすることが多いようです。
クラス
スクリプトでクラスを使うこともないかと思いますが軽く。。。
クラスの書式は下記
1 2 3 |
class クラス名 < 継承クラス 処理 end |
例
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 Hoge @@hoge = 3 #クラス変数 # イニシャライザ def initialize @hogehoge = 6 #インスタンス変数外からアクセスするにはたぶんセッターゲッターが必要 end def fuga @@hoge + @hogehoge end end class Foo < Hoge def fuga super + 100 end def Foo.piyo @@hoge + 1 end def piyopiyo(foo) @hogehoge + foo end end hoge = Hoge.new puts hoge.fuga #9 puts Foo.piyo #4 foo = Foo.new puts foo.fuga #109 puts foo.piyopiyo(5) #11 |
呼び出し制限として private, public, protected があるみたいです
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Hoge # デフォルトはpublic def foo end private # これ以降private def fuga end def piyo end end |
メソッドの前につけるやつばっかだったのでちょっと不思議。
文字列操作
文字列操作色々
参考
長さ
1 |
puts "あいうえお".size #5 |
抜き出し
1 2 3 4 5 |
puts "あいうえお"[2] #う puts "あいうえお"[-2] #え puts "あいうえお"[1, 2] #いう puts "あいうえお"[-2, 2] #えお puts "あいうえお"[2 .. 3] #うえ |
結合
1 2 3 4 5 6 |
puts "あいう" + "えお" #あいうえお # こっちのが速いらしい str = "あいう" str.concat("えお") puts str #あいうえお |
大文字・小文字変換
1 2 3 4 5 6 7 8 9 |
puts "abc".upcase #ABC str = "abc" str.upcase! puts str #ABC puts "ABC".downcase #abc str = "ABC" str.downcase! puts str #abc |
トリミング
1 2 3 4 |
str = " 123 " puts str.strip #"123" puts str.lstrip #"123 " puts str.rstrip #" 123" |
置換
1 2 3 4 5 6 |
str = "あいうえおあいうえお" str["いう"] = "A" puts str #あAえおあいうえお str = "あいうえおあいうえお" puts str.gsub(/いう/, "A") #あAえおあAえお |
検索
1 2 3 4 |
puts "あいうえおあいうえお".index("いう") #1 puts "あいうえおあいうえお".rindex("いう") #6 puts "あいうえおあいうえお".include?("いう") #true |
Array
配列操作いろいろ
参考
初期化
1 2 3 4 |
array = ["a", "b", "c"] # 範囲オブジェクトからも生成できるらしい (1..5).to_a # [1, 2, 3, 4, 5] |
追加・削除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
array = ["a", "b", "c"] # 追加 array[3] = "d" array.push("e") p array #["a", "b", "c", "d", "e"] #削除 array.delete("a") #[index番号, 削除する個数]で指定 array[0,3] = [] p array #["e"] |
その他便利メソッド
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 |
# 結合 arrayA = ["a", "b", "c"] arrayB = ["d", "e", "f"] arrayA.concat(arrayB) p arrayA #["a", "b", "c", "d", "e", "f"] # 文字列結合 puts ["a", "b", "c"].join("") #abc # map p [1, 2, 3].map { |num| num*2 } #[2, 4, 6] # 絞り込み p [1, 2, 3, 4, 5].select { |num| num%2 == 0 } #[2, 4] # 重複削除 p ["a", "a", "b", "c", "c", "a"].uniq #["a", "b", "c"] # カウント p ["a", "a", "b", "c", "c", "a"].count("a") #3 p ["a", "b", "c"].length #3 # 反転 array = ["a","b","c"] p array.reverse #["c","b","a"] p array #["a","b","c"] array.reverse! p array #["c","b","a"] # ソート array = ["bc", "abc", "d", "scdeft", "z"] p array.sort #["abc", "bc", "d", "scdeft", "z"] p array.sort_by { |value| value.size } #["d", "z", "bc", "abc", "scdeft"] # 繰り返し array = ["abc", "def", "ghi"] array.each { |s| s.capitalize! } p array #["Abc", "Def", "Ghi"] |
スクリプトをつくる
なんとなく書き方がわかったところで ios-snapshot-test-case で作成したスクショ一覧をいい感じに Markdown で出力してみます!
https://gist.github.com/imaizume/6aa2537c1c6778b50873c813eb7a15f1ほぼこここのやつ使えばできますがちょっとだけ書き換えてみます。
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#!/usr/bin/env ruby PATTERN_OF_OS_VERSION = %r{\d+_\d+} PATTERN_OF_SCREEN_SIZE = %r{\d+x\d+} NUMBER_OF_ROWS = 5 # Change here for number of your test case NUMBER_OF_COLUMNS = 4 # Change here in your favor IMAGE_WIDTH = 100 def create_markdown(file_name) file_name = create_file_name(file_name) reference_image_dir = "./ReferenceImages_64/*" markdowns = "# #{file_name}\n\n" Dir.glob(reference_image_dir).sort.each do |test_file_path| test_title = test_file_path.split("/").last if markdowns.include?("##") then markdowns += "<div style='page-break-before:always'></div>\n\n" end markdowns += "## #{test_title}\n\n" reference_image_path = "#{test_file_path}/*" Dir.glob(reference_image_path).sort.each_slice(NUMBER_OF_COLUMNS) do |slice| rows = Array.new(NUMBER_OF_ROWS) { Array.new(0, 0) } slice.each do |screen_shot| tokens = screen_shot[/test(.+)/, 1].split("_") header = tokens[1] postfix = tokens[2..].join("_") os = postfix.match(PATTERN_OF_OS_VERSION)[0].gsub('_', '.') screen_size = convert_screen_size_into_device_name(postfix.match(PATTERN_OF_SCREEN_SIZE)[0]) src = "../#{screen_shot}" imageTag = "<img src='#{src}' width='#{IMAGE_WIDTH}' style='border: 1px solid #999' />" rows[0].push header rows[1].push ":---:" rows[2].push os rows[3].push screen_size rows[4].push imageTag end markdowns += rows.map { |row| row.join('|').prepend('|').concat('|') + "\n" }.join markdowns += "\n" end end report_dir = "./Reports" if !Dir.exist?(report_dir) then Dir.mkdir(report_dir) end report_file_path = "#{report_dir}/#{file_name}.md" status = FileTest.exist?(report_file_path) ? "UPDATED" : "CREATED" File.write(report_file_path, markdowns) puts "[#{status}] #{report_file_path}" end def convert_screen_size_into_device_name(screen_size) case screen_size when "320x568" return 'iPhone SE' when "375x667" return 'iPhone 8' when "414x736" return 'iPhone 8 Plus' when "375x812" return 'iPhone 11Pro' when "414x896" return 'iPhone 11Pro Max' else return 'iPhone' end end def create_file_name(file_name) if file_name.nil? or file_name.empty? then file_name = "Test" end now = Time.new time = now.strftime("%Y%m%d") return "#{file_name}_#{time}" end puts '[START] Generating Screenshots Preview' create_markdown(ARGV[0]) puts '[FINISH] Generating Screenshots Preview' |
スクショはこういう感じのやつ
1 |
ReferenceImages_64/テスト1/testView_画面A_iPhone_13_5_414x896.png |
上のスクリプトを markdown_generator.rb という名前で ReferenceImages_64 と同階層に保存し下記のようにターミナルで実行する
1 |
ruby markdown_generator.rb Hoge |
そうすると Reports ディレクトリに Hoge_20200906.md というファイルが出力されます。(_以降は生成日です)
おわりに
これで Ruby でちょっとしたスクリプトが書けるようになりました!!
色々あって git にあげることができなかったので最終的に PDF に出力して共有することにしました。スクリプトで全部やりたかったのですが PDF 変換するいいやつがなかったので MacDown で出力してプレビューでサイズを落とすことにしました。。。
最終的にはこういう PDF になりました!!
参考
- 公式ドキュメント
- Ruby 2.7.0 リファレンスマニュアル
- とほほのRuby入門
- ruby よく使うString型のメソッド
- Ruby 文字列から文字を削除するメソッドまとめ
- ruby 配列 基本操作まとめ
- スナップショットテスト実戦投入(スライド)
- ios-snapshot-test-caseを快適に運用する5つのtips
コメント
I’ll right away grasp your rss as I can not to find your e-mail subscription link or e-newsletter service. Do you have any? Please let me understand in order that I may subscribe. Thanks.|
It’s amazing designed for me to have a web page, which is valuable designed for my experience. thanks admin|
I take pleasure in, lead to I discovered just what I was looking for. You have ended my four day lengthy hunt! God Bless you man. Have a nice day. Bye|
Woah! I’m really loving the template/theme of this site. It’s simple, yet effective. A lot of times it’s difficult to get that “perfect balance” between user friendliness and appearance. I must say you have done a awesome job with this. Also, the blog loads extremely quick for me on Firefox. Superb Blog!|
We are a gaggle of volunteers and starting a brand new scheme in our community. Your website provided us with useful information to work on. You’ve performed a formidable job and our whole neighborhood will likely be grateful to you.|
Helpful info. Fortunate me I found your site accidentally, and I am stunned why this coincidence did not happened earlier! I bookmarked it.|