ようへいの日々精進XP

よかろうもん

2018 年 08 月 11 日 (土)

ジョギング

  • 香椎浜 x 2 周
  • 右足踵付近に違和感, 痛みに変わる前になんとかしたい

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

暑い

お陰様で洗濯物だけはよく乾く.

博多デート

奥さんが博多の美容院に行くというので, 待ち合わせて博多でデート...といきたかったんだけど, 軒並み飲食店に入れず. 結局, いつもの串カツのお店で夕飯を済ませる. 串カツが美味しいので良しとする. その後, ヨドバシカメラロナウドが CM に出ているシックスパッドを体感したり, ThinkPad L380 でいいよなあと実機を触りながら思った.

博多駅に戻ると改札に黒山の人だかりで, 嫌な予感がしたんだけど, 案の定, 鹿児島本線に血痕が付いてて警察が現場検証しているので運転見直しという状態. さて, これからどうしようか.

今日のるびぃ exercism 編 〜 Two Fer (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

これも Hello World に近い感じで, クラスメソッドに対して引数 (name) があれば, 以下のように出力する.

"One for #{name}, one for me

引数がなければ, 以下のように出力する.

One for you, one for me

テスト

require 'minitest/autorun'
require_relative 'two_fer'

# Common test data version: 1.1.0 c080bdf
class TwoFerTest < Minitest::Test
  def test_no_name_given
    # skip
    assert_equal "One for you, one for me.", TwoFer.two_fer
  end

  def test_a_name_given
    # skip
    assert_equal "One for Alice, one for me.", TwoFer.two_fer("Alice")
  end

  def test_another_name_given
    # skip
    assert_equal "One for Bob, one for me.", TwoFer.two_fer("Bob")
  end

... 略 ...

  def test_bookkeeping
    skip
    assert_equal 1, BookKeeping::VERSION
  end
end

実装

class TwoFer
  class << self
    def two_fer(name = nil)
      return "One for you, one for me." if name == nil
      "One for #{name}, one for me."
    end
  end
end

クラスメソッドの定義については, 上記以外のパターンもあるけど割愛.

Run Test

$ ruby two_fer_test.rb
Run options: --seed 42860

# Running:

..S.

Finished in 0.001849s, 2163.3315 runs/s, 1622.4987 assertions/s.

4 runs, 3 assertions, 0 failures, 0 errors, 1 skips

You have skipped tests. Run with --verbose for details.

いい感じ.

今日の AWS ~ AWS 認定デベロッパー – アソシエイトレベルサンプル試験を解く (1) ~

公開されているサンプル試験問題を解く. なぜ, その答えになるのかをちゃんと理解する必要がある.

Q1. SQS の仕様について

設問

次の文のうち、SQS について正しく述べているものはどれですか?

A. メッセージは 1 回だけ配信され、先入れ先出しの順序で配信される。
B. メッセージは 1 回だけ配信され、配信順序は決まっていない。
C. メッセージは 1 回以上配信され、先入れ先出しの順序で配信される。
D. メッセージは 1 回以上配信され、配信順序は決まっていない。

正答

  • D (メッセージは 1 回以上配信され, 配信順序は決まっていない.)

メモ

  • AWS Black Belt Tech シリーズ 2016 - Amazon SQS / Amazon SNS
  • SQS で利用する識別子
    • Queue URL
    • Message ID
    • Receipt Handle (受信ハンドル)
      • 同一メッセージでも, 受信ハンドルは異なるので, メッセージの削除の際は最新の受信ハンドルを用いる
  • SQS のコスト
    • 毎月 100 万キューイングまでは無料
    • 同一リージョン内での SQS と EC2 インスタンスのデータ転送は無料
  • メッセージは削除しない限りは複数回受信が可能, また, 受信の順番は送信の順番とは異なる場合がある (配信の順序は決まっていない)
    • 順序を保証しなければいけない場合, アプリケーションの実装で頑張る必要がある
    • 一部のリージョンでは FIFO キューという送受信の順序が同じキューも利用可能

Q2. AMI の仕様について

設問

EC2 インスタンスAmazon マシンイメージ(AMI)から起動されます。次のうち、パブリック AMI について当てはまるものはどれですか ?

A. そこの AWS リージョンであっても EC2 インスタンスを起動するために使用できる。
B. その AMI が格納されている国で EC2 インスタンスを起動するためにのみ使用できる。
C. その AMI が格納されている AWS リージョンで EC2 インスタンスを起動するためにのみ使用できる。
D. その AMI が格納されている AWS アベイラビリティーゾーンで EC2 インスタンスを起動するためにのみ使用できる。

正答

  • C (その AMI が格納されている AWS リージョンで EC2 インスタンスを起動するためのみ使用出来る.)

メモ

  • Amazon マシンイメージの略
  • パブリック AMI については, リージョン毎に AMI が存在する

Q3. 引き続き, SQS の仕様

設問

... SQS キューからタスクを処理して実行するバックエンドインスタンスは、キューを可能な限り頻繁にポーリングして、処理を早く行えるようにしています。しかし短い周期でのポーリングによって、処理すべきタスクがない空のレスポンスが返り CPU が無駄に消費される可能性があります。空のレスポンスの数を減らすには、どうすればよいですか?

A. キューの VisibilityTimeout 属性を 20 秒に設定する。
B. キューの ReceiveMessageWaitTimeSeconds 属性を 20 秒に設定する。
C. キューの MessageRetentionPeriod 属性を 20 秒に設定する。
D. メッセージの DelaySeconds パラメータを 20 秒に設定する。

正答

  • B (キューの ReceiveMessageWaitTimeSeconds 属性を 20 秒に設定する)

メモ

  • ReceiveMessageWaitTimeSeconds (いわゆるロングポーリング) を設定する
  • ReceiveMessageWaitTimeSeconds とは
    • 返信するメッセージがない場合, 偽の空のレスポンスを排除して空のレスポンスの数を減らすことで, SQS の使用コストを削減する
  • VisibilityTimeout とは
    • 複数の consumer が稼働している場合, 1 つの consumer が受信した後, 他の consumer には一時的 (デフォルトは 30 秒) メッセージを見せない機能
    • consumer1 が処理に失敗しても, 他の consumer で処理が継続出来る
  • MessageRetentionPeriod
    • SQS がメッセージを保持する秒数
    • デフォルト値は 345600 秒 (4 日)
  • DelaySeconds
    • 遅延キュー
    • キューへの新しいメッセージの配信を数秒延期することが出来る
    • デフォルト値は 0 秒

フムフム.

2018 年 08 月 10 日 (金)

ジョギング

  • お休み

日課

  • お休み

AWS Certified Solutions Architect - Associate - RECERTIFICATION

要は AWS の認定資格のうち, ソリューションアーキテクトの入門編であるアソシエイトレベルの試験を受けてきた. すごく疲れたけど, 一応, 合格することが出来て無事に再認定された.

引き続き, 試験の予定を入れているので, 今年中にプロフェッショナルレベルを含めた 5 つの資格を取るぞ.

今日のるびぃ exercism 編 〜 Nucleotide Count (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

引数で与えられた DNA 文字列に各ヌクレオチドが何回出現するかを計算する.

テスト

require 'minitest/autorun'
require_relative 'nucleotide_count'

class NucleotideTest < Minitest::Test
  def test_empty_dna_strand_has_no_adenosine
    assert_equal 0, Nucleotide.from_dna('').count('A')
  end

  def test_repetitive_cytidine_gets_counted
    skip
    assert_equal 5, Nucleotide.from_dna('CCCCC').count('C')
  end

  def test_counts_only_thymidine
    skip
    assert_equal 1, Nucleotide.from_dna('GGGGGTAACCCGG').count('T')
  end

  def test_counts_a_nucleotide_only_once
    skip
    dna = Nucleotide.from_dna('CGATTGGG')
    dna.count('T')
    dna.count('T')
    assert_equal 2, dna.count('T')
  end

  def test_empty_dna_strand_has_no_nucleotides
    skip
    expected = { 'A' => 0, 'T' => 0, 'C' => 0, 'G' => 0 }
    assert_equal expected, Nucleotide.from_dna('').histogram
  end

  def test_repetitive_sequence_has_only_guanosine
    skip
    expected = { 'A' => 0, 'T' => 0, 'C' => 0, 'G' => 8 }
    assert_equal expected, Nucleotide.from_dna('GGGGGGGG').histogram
  end

  def test_counts_all_nucleotides
    skip
    s = 'AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC'
    dna = Nucleotide.from_dna(s)
    expected = { 'A' => 20, 'T' => 21, 'G' => 17, 'C' => 12 }
    assert_equal expected, dna.histogram
  end

  def test_validates_dna
    skip
    assert_raises ArgumentError do
      Nucleotide.from_dna('JOHNNYAPPLESEED')
    end
  end
end

実装

class Nucleotide
  class << self
    def from_dna(dna)
      if ignore_word_included?(dna)
        raise ArgumentError
      end
      @dna = dna
      self
    end

    def count(w)
      @dna.count(w)
    end

    def histogram
      hist = Hash['A' => 0, 'T' => 0, 'C' => 0, 'G' => 0]
      @dna.split('').uniq.each do |w|
        hist[w] = @dna.count(w)
      end
      hist
    end

    private

    def ignore_word_included?(dna)
      (dna.split('').select { |w| ! w.match(/A|T|C|G/) }).size > 0 ? true : false
    end
  end
end

Run Test

$ ruby nucleotide_count_test.rb 
Run options: --seed 57489

# Running:

........

Finished in 0.001976s, 4049.0522 runs/s, 4049.0522 assertions/s.

8 runs, 8 assertions, 0 failures, 0 errors, 0 skips

メモ

  • メソッドチェインの実装方法を学べた
  • 他の実装についても検討する

今日の AWS ~ オブジェクトストレージ ~

S3

基本仕様

  • S3 にデータを保存するには, 特定のリージョンのバケットと呼ばれる格納先を作成し, その中に Key-Value 形式でファイルをアップロードする
  • バケット名は全世界で一意であること
  • 各オブジェクトには URL が付与され, HTTPS によるアクセスが可能
  • マルチパートアップロード機能を利用した場合, 1 オブジェクトあたり 5TB
  • マルチマーとアップロード機能を利用しない場合, 1 オブジェクトあたり 5GB

ストレージクラス

  • スタンダードクラス
    • 耐久性 99.999999999%
    • 3 ヶ所のデータセンターに複製される
  • 冗長化クラス
    • 耐久性 99.99%
    • 利用料金はスタンダードクラスと比較すると安価

整合性

  • S3 は格納したデータを複数のデータセンターに複製することで高いデータ耐久性を実現している
  • 但し, 書き込み, 更新, 削除時のデータの整合性について注意が必要となる

以下, オブジェクトに対するアクション毎にざっくりと整理.

オブジェクトに対するアクション 整合性の種類 メモ
新規書き込み 書き込み後の読み取り整合性 アップロード直後は, オブジェクトにアクセス出来ないことがある
上書き書き込み 結果整合性 上書き後, オブジェクトにアクセスしても古いデータが返されることがある
削除 結果整合性 削除後, 削除したはずのデータにアクセス出来ることがある

アクセス制限とセキュリティ

  • アクセスコントロールリスト (ACL)
    • バケットとオブジェクトそれぞれについて, 読み取り, 書き込み許可を他の AWS アカウントに与えることが出来る
    • 条件付きアクセス許可, アクセス拒否設定は出来ない
    • 自アカウント内の IAM ユーザー, グループのアクセス権を制限することも出来ない
  • バケットポリシー
    • 自アカウント内の IAM ユーザーやグループ, 他のアカウントのユーザーに対してアクセス許可を与えることが出来る
    • 条件付きアクセス許可やアクセス拒否を設定することも出来る
  • IAM ポリシー
    • S3 へのアクセス許可を設定した IAM ポリシーを自アカウント内の IAM ユーザーやグループ, ロールに割り当てることが出来る
    • 条件付きアクセス許可やアクセス拒否を設定することも出来る
    • 他アカウントを指定したアクセス権は設定出来ない

その他, アクセス期間を限定した署名 (期限) 付き URLも設定可能.

オブジェクトの暗号化とアクセスログ

  • AWS が管理する鍵やユーザーが管理する鍵を使って S3 上で暗号化するサーバーサイド暗号化
  • クライアント側で事前に暗号化したデータを S3 バケットにアップロードするクライアントサイド暗号化
  • アクセスログはベストエフォートで記録される為, 完全性は保証されない, また, タイムラグが発生する

静的 Web サイトホスティング機能

  • S3 は Web サイトをホスティング出来る
  • 静的な Web サイトに限られる
  • EC2 を利用するよりも運用の負荷がコストを抑えることが出来る
  • 指定したドメイン名でアクセスさせる為には, Route53 等の DNS サービスにより名前解決が必要となる

バージョニング機能

  • バケット単位で指定可能
  • オブジェクトの意図しない上書きや削除に対して有効 (操作前のオブジェクトを復元することが出来る)

ライフサイクル機能と Glacier へのアーカイブ

  • 通常はほとんどアクセスすることがないようなデータは Glacier に保存することで, データの保存コストを抑えることが出来る
  • Glacier へのデータ保存は, ライフサイクル機能を利用するか, SDK を利用して直接格納する
  • Glacier からデータを取り出す場合, 3 ~ 5 時間程度, Glacier に保存している 5% の容量まではデータ取り出し費用は無料

フムフム.

2018 年 08 月 09 日 (木)

ジョギング

  • 香椎浜 x 2 周
  • いつもよりだいぶん涼しい感じ
  • 右足踵付近に違和感 (軽い痛み)

日課

  • お休み

JAWS-UG 福岡 もくもく会

  • fukuoka.rb の雰囲気を参考にさせて頂いて, 似たような感じで開催してみた
  • アメンバー以外に二名の方に参加して頂いて, 軽い雑談を交えつつ, ビール呑みながらいい感じで手を動かせていたんではと思う
  • 出来るだけ, 間を開けない感じで次回も開催したい

今日のるびぃ exercism 編 〜 rna-transcription (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

以下のように, DNA の配列を渡すと, RNA 相補体を返すような実装.

DNA  RNA
G -> C
C -> G
T -> A
A -> U

テスト

require 'minitest/autorun'
require_relative 'rna_transcription'

# Common test data version: 1.0.1 cb1fd3a
class RnaTranscriptionTest < Minitest::Test
  def test_rna_complement_of_cytosine_is_guanine
    # skip
    assert_equal 'G', Complement.of_dna('C')
  end

  def test_rna_complement_of_guanine_is_cytosine
    skip
    assert_equal 'C', Complement.of_dna('G')
  end

  def test_rna_complement_of_thymine_is_adenine
    skip
    assert_equal 'A', Complement.of_dna('T')
  end

  def test_rna_complement_of_adenine_is_uracil
    skip
    assert_equal 'U', Complement.of_dna('A')
  end

  def test_rna_complement
    skip
    assert_equal 'UGCACCAGAAUU', Complement.of_dna('ACGTGGTCTTAA')
  end

  def test_correctly_handles_invalid_input_rna_instead_of_dna
    skip
    assert_equal '', Complement.of_dna('U')
  end

  def test_correctly_handles_completely_invalid_dna_input
    skip
    assert_equal '', Complement.of_dna('XXX')
  end

  def test_correctly_handles_partially_invalid_dna_input
    skip
    assert_equal '', Complement.of_dna('ACGTXXXCTTAA')
  end
... 略 ...
  def test_bookkeeping
    skip
    assert_equal 4, BookKeeping::VERSION
  end
end

実装

# file: rna_transcription.rb
class Complement
  class << self
    def of_dna(rna)
      dna = ''
      rna.split('').each do |r|
        dna << 'G' if r == 'C'
        dna << 'C' if r == 'G'
        dna << 'A' if r == 'T'
        dna << 'U' if r == 'A'
      end
      dna.to_s.size == rna.size ? dna.to_s : ''
    end
  end
end

テスト実行

$ ruby rna_transcription_test.rb 
Run options: --seed 58737

# Running:

.......S.

Finished in 0.001557s, 5781.8396 runs/s, 5139.4130 assertions/s.

9 runs, 8 assertions, 0 failures, 0 errors, 1 skips

You have skipped tests. Run with --verbose for details.

とりあえず, パブリッシュ済み.

メモ

  • DNA とか RNA とか理解出来てないけど, テストを実行すれば, 一応, 動きは解った
  • 別の実装について模索中

今日の AWS ~ コンピューティング ~

EC2

EC2 のライフサイクル

  • ライフサイクル
    • pending
    • running
    • rebooting
    • stopping
    • shutting-down
    • stopped
    • terminated
  • ステータスチェック
    • System Status Check (インフラストラクチャ (H/W, ハイパーバイザ) のチェック)
    • Instance Status Check (OS のチェック)
  • オンデマンドインスタンスの課金
    • running になった時点で課金が発生, stopped 又は terminated になるまで発生

EBS とインスタンスストア

EBS インスタンスストア
データ特性 不揮発性 (永続化) 揮発性
性能 数百 ~ 20,000 IOPS 最大 300,000 IOPS
価格 GB 課金 無料

EC2 には, EBS-backend インスタンスと, Instance store-backend (S3-backend) インスタンスの 2 タイプが存在する. 両者の違いは以下の通り.

  • EBS-backend インスタンスは停止と起動, 再起動, 削除が可能
  • Instance store-backend (S3-backend) インスタンスは再起動と, 削除, 尚, 停止は出来ない

EBS のタイプ

  • General Purepose SSD (gp2)
    • 1GB ~ 16TB
    • 3IOPS/GB のベースパフォーマンス, 最大 10,000IOPS, ベースパフォーマンスが 3,000IOPS 未満の場合, 3,000IOPS までバースト機能
    • 容量課金
    • 一般的な利用 (汎用)
  • Provisioned IOPS SSD (io1)
    • 4GB ~ 16TB
    • 容量あたり 50 IOPS を指定可能, 最大 20,000IOPS (最新だと, 最大 32,000 IOPS)
    • 容量 + 指定した IOPS 課金
    • 10,000 IOPS を超える性能が求められるアプリケーション, データベース等で利用
  • スループット最適化 HDD (st1)
  • コールド HDD (sc1)
  • Magnetic
    • 1GB ~ 1TB
    • 平均 100 IOPS
    • 容量 + 発生した IO 数
    • IO があまり発生せず, コストが重視される構成で利用

Provisioned IOPS SSD で, EBS ディスク性能を高めることが出来るが, 通常の EC2 インスタンスでは, 通常のネットワーク帯域と EBS 用のネットワーク帯域が共有されている為, 十分に性能を引き出すことが出来ないが, EBS 最適化インスタンスを利用することで EBS 専用の帯域が確保される為, EBS の I/O が安定する. Provisioned IOPS SSD では, EBS の高い I/O 性能を活かす為にも, EBS 最適化インスタンスの利用が推奨される. (インスタンスタイプが大きい程, 使える帯域が大きい)

EBS スナップショット

  • 任意のタイミングでスナップショットを作成することが出来る
  • スナップショットは S3 に保存される
  • スナップショットは圧縮され, 差分のデータのみが保存される為, 容量を抑えることが出来る (圧縮後の容量に対して課金される)
  • データの整合性を保つ為にディスク I/O を停止する必要があり, 対象の EBS ボリュームをアンマウントしてからスナップショットを取得することが推奨されている
  • 取得開始時点の EBS ボリューム内のデータをキャプチャして, それ以降の書き込みはキャプチャ対象外
  • 復元はスナップショットの元となったボリュームサイズよりも大きなディスクサイズを指定して復元することが出来る
  • EBS ボリュームは AZ サービスであり, 同一 AZ 内の EC2 のみにアタッチすることが出来る
  • リージョンをまたぎたい場合には, スナップショットを利用して別リージョンにコピーして EBS ボリュームを復元する

プレイスメントグループ

  • 単一の AZ にプレイスメントグループ を作成すると EC2 間のネットワーク接続を高速化することが出来る

Dedicated インスタンス

フムフム.

2018 年 08 月 08 日 (水)

ジョギング

  • 香椎浜 x 2 周
  • いつもよりだいぶん涼しい感じ
  • 引き続き, 足にもすごく疲労が溜まっている感

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

おなら

  • 奥さんのおならが頻発している

今日のるびぃ exercism 編 〜 helloworld (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

hello world!!!

テストコード

begin
  gem 'minitest', '>= 5.0.0'
  require 'minitest/autorun'
  require_relative 'hello_world'
rescue Gem::LoadError => e
  puts "\nMissing Dependency:\n#{e.backtrace.first} #{e.message}"
  puts 'Minitest 5.0 gem must be installed for the Ruby track.'
rescue LoadError => e
  puts "\nError:\n#{e.backtrace.first} #{e.message}"
  puts DATA.read
  exit 1
end

# Common test data version: 1.0.0 4b9ae53
class HelloWorldTest < Minitest::Test
  def test_say_hi
    # skip
    assert_equal "Hello, World!", HelloWorld1.hello
    assert_equal "Hello, World!", HelloWorld2.hello
    assert_equal "Hello, World!", HelloWorld3.hello
  end
end
... 略 ...

実装

# 実装 1
class HelloWorld1
  def self.hello
    'Hello, World!'
  end
end

# 実装 2
class HelloWorld2
  class << self
    def hello
      'Hello, World!'
    end
  end
end

# 実装 3
module HelloWorldModule
  def hello
    'Hello, World!'
  end
end

class HelloWorld3
  extend HelloWorldModule
end

テスト実行

$ ruby hello_world_test.rb 
Run options: --seed 26958

# Running:

.

Finished in 0.001473s, 678.8608 runs/s, 2036.5824 assertions/s.

1 runs, 3 assertions, 0 failures, 0 errors, 0 skips

メモ

今日の AWS ~ VPC ~

VPC

  • Virtual Private Network
    • 10.0.0.0/16
    • 172.16.0.0/16
    • 192.168.0.0/16
  • サブネット
    • 配置するサーバーの役割に応じて作成するのが一般的
  • ゲートウェイ
    • インターネットへの出入り口 (IGW)
    • オンプレと VPN専用線で通信する為の出入り口 (VGW)
  • ルートテーブル
    • サブネット毎にインターネットアクセスを許可, 不許可の制限をかけることが出来る
    • IGW が定義されているルートテーブルがアタッチされている場合, パブリックサブネットとなる
    • VPC 内の通信はルートテーブルでは制御出来ない
  • NAT インスタンス
    • プライベートサブネットからインターネットにアクセスする為に利用する
    • 「送信元 / 送信先チェック」を無効化する

EC2 インスタンスの IP アドレス

  • Public IP
  • Elastic IP

セキュリティグループとネットワーク ACL

セキュリティグループ

  • セキュリティグループは EC2 や ELB, RDS 等のインスタンス毎のファイヤーウォール
  • デフォルトでアウトバウントはフルオープン
  • ステートフル (インバウンドで許可していた受信トラフィックの戻りのトラフィックは暗黙的に許可される)

ネットワーク ACL

  • サブネット毎のファイヤーウォール
  • インバウンド, アウトバウントのアクセス制御が必要, 優先順位をつけて設定する
  • ステートレス

VPC ピア接続

  • 2 つの VPC を接続する昨日
  • プライベート IP 同士で通信を行う
  • 双方の VPC に PCX というゲートウェイ相当のインターフェースが作成され, これをルートテーブルの送信先ターゲットとして設定する
  • 制約
    • 接続する VPC は同一リージョンに存在していること (リージョンを跨げない)
    • プライベートネットワークアドレス空間は重複してはいけない
    • 1 対 1 の接続となる (VPC A と VPC B, VPC B と VPC C, VPC A と VPC C という感じで, 個別にピア接続する必要がある)

フムフム.

2018 年 08 月 07 日 (火)

ジョギング

  • 香椎浜 x 2 周
  • 足にもすごく疲労が溜まっている感

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

奥さんが体調を崩す

  • 夏バテかな〜
  • 出来るだけ食べて, 夏バテに負けないように!

今日のるびぃ exercism 編 〜 gigasecond (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

1,000,000,000 秒後を計算する.

テストコード

require 'minitest/autorun'
require_relative 'gigasecond'

# Common test data version: 1.0.0 61e7d70
class GigasecondTest < Minitest::Test
  def test_date_only_specification_of_time
    assert_equal Time.utc(2043, 1, 1, 1, 46, 40), Gigasecond.from(Time.utc(2011, 4, 25, 0, 0, 0))
  end

  def test_second_test_for_date_only_specification_of_time
    assert_equal Time.utc(2009, 2, 19, 1, 46, 40), Gigasecond.from(Time.utc(1977, 6, 13, 0, 0, 0))
  end

  def test_third_test_for_date_only_specification_of_time
    assert_equal Time.utc(1991, 3, 27, 1, 46, 40), Gigasecond.from(Time.utc(1959, 7, 19, 0, 0, 0))
  end

  def test_full_time_specified
    assert_equal Time.utc(2046, 10, 2, 23, 46, 40), Gigasecond.from(Time.utc(2015, 1, 24, 22, 0, 0))
  end

  def test_full_time_with_day_roll_over
    assert_equal Time.utc(2046, 10, 3, 1, 46, 39), Gigasecond.from(Time.utc(2015, 1, 24, 23, 59, 59))
  end

... 略 ...

  def test_bookkeeping
    # skip
    assert_equal 6, BookKeeping::VERSION
  end
end

実装

module BookKeeping
  VERSION = 6
end

class Gigasecond
  class << self
    def from(t)
      t + 1_000_000_000
    end
  end
end

テスト実行

$ ruby gigasecond_test.rb
Run options: --seed 9573

# Running:

......

Finished in 0.000849s, 7065.5483 runs/s, 7065.5483 assertions/s.

6 runs, 6 assertions, 0 failures, 0 errors, 0 skips

ひとまず, LGTM なのでサブミットする.

メモ

  • 英語が読めないので, テストを走らせて概要をつかむことが重要
  • テストを走らせたら, 意外に簡単だった (きっと, 単に問題が簡単なやつなんだろな)

今日の AWS ~ 責任分担セキュリティモデルと認証 ~

責任分担セキュリティモデル

  • 利用者と AWS が協力してセキュリティを高める考え方
  • サービス毎に責任範囲が異なる
  • 例えば, EC2 のようなインフラストラクチャサービスについては, AWS の責任範囲としては, 物理ホストやストレージ, ネットワーク等のインフラストラクチャまでとなる

IAM

  • AWS 内のユーザー管理, AWS リソースに対するアクセス制御を行うためのサービス
  • 作成した IAM グループや IAM ユーザーにはデフォルトでは何の権限も与えられていない
  • 権限を付与する場合には, 必要最低限の権限を割り当てるようにする
  • 許可と拒否, 双方の IAM ポリシーを付与する場合, 拒否のポリシーが優先される
  • IAM ロールの利用が推奨される

ID フェデレーション

以下は, ID ブローカーを使った, 一般的なフェデレーションの例.

  1. ユーザーが社内の ID ブローカーにアクセス
  2. ID ブローカーは AD や LDAP でユーザーを認証
  3. ID ブローカーが STS から一時的な認証を取得
  4. 一時的な認証情報を使って, ユーザーが S3 バケットにアクセス

AssumeRole

フムフム.

2018 年 08 月 06 日 (月)

ジョギング

  • 香椎浜 x 2 周
  • 引き続き, 徹底的に熱い (暑いではなく, もはや熱い)
  • 流石にクラクラしてしまった
  • 足にもすごく疲労が溜まっている感

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

73 回目の広島に原爆が投下された日

  • 全ての被災者に合掌
  • 年々, 報道での取り上げられ方が小さくなっている感

今日のるびぃ ~ いろいろ ~

色々と気になったことをメモる. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

const_missing

class Object
  def const_missing(const)
    const = '-1'
  end
end

class Class
  def const_missing(const)
    const = '0'
  end
end

class Cls1
  def const_missing(const)
    const = '1'
  end
end

class Cls2 < Cls1
  CONST_1 = '123'
  def method1
    puts CONST_1
    puts CONST_2
  end
end

Cls2.new.method1

上記の例だと, CONST_2 において, Class#const_missing まで遡る.

... 略 ...
irb(main):026:0> 
irb(main):027:0* Cls2.new.method1
123
0
=> nil

さらに, 以下のような場合には...

class Object
  def const_missing(const)
    const = '-1'
  end
end

class Class
  def const_missing(const)
    const = '0'
  end
end

class Cls1
  def self.const_missing(const)
    const = '1'
  end
end

class Cls2 < Cls1
  CONST_1 = '123'
  def method1
    puts CONST_1
    puts CONST_2
  end
end

Cls2.new.method1
  • const_missing はクラスメソッドとして定義されている必要がある為, Cls2 から継承ツリーを辿って, 最初に見つかる Cls1.const_missing で捕捉される
irb(main):026:0> 
irb(main):027:0* Cls2.new.method1
123
1
=> nil

正規表現

# 正規表現 1
irb(main):001:0> %r|http://www(\.)(.*)/| =~ "http://www.abc.com/"
=> 0
irb(main):002:0> $0
=> "irb"
irb(main):003:0> $1
=> "."
irb(main):004:0> $2
=> "abc.com"
# 正規表現 2
irb(main):005:0> %r|(http://www(\.)(.*)/)| =~ "http://www.abc.com/"
=> 0
irb(main):006:0> $0
=> "irb"
irb(main):007:0> $1
=> "http://www.abc.com/"
irb(main):008:0> $2
=> "."
irb(main):009:0> $3
=> "abc.com"
  • () 内のパターンにマッチした部分文字列が $1 から始まる特殊変数に代入されている
  • $0スクリプト名 (上記の例だと irb) が入る
  • 正規表現 2」 の場合, 最初の () には http://www.abc.com/ がマッチする

map, collect, inject

irb(main):001:0> [1, 2, 3].map {|x| x ** 2}
=> [1, 4, 9]
irb(main):002:0> [1, 2, 3].collect {|x| x ** 2}
=> [1, 4, 9]
irb(main):003:0> [1, 2, 3].inject([]) {|x, y| x << y ** 2}
=> [1, 4, 9]
  • inject はリストの畳み込み演算を行う
# リストの合計
irb(main):004:0> p [2, 3, 4, 5].inject {|result, item| result + item }
14
=> 14
# リストの自乗和
irb(main):005:0> p [2, 3, 4, 5].inject(0) {|result, item| result + item**2 }
54
=> 54

lazy

p (1..Float::INFINITY).lazy.map {|x|
  x ** 2
}.take(3).inject(0, &:+)

Enumerable#lazy は実際に値が必要になるまで値を生成せず, take や first 等, 値を返すメソッドが呼ばれた際に必要な数だけ値を評価し, リストとして返すメソッドである.

irb(main):006:0> p (1..Float::INFINITY).lazy.map {|x|
irb(main):007:1*   x ** 2
irb(main):008:1> }.take(3).inject(0, &:+)
14
=> 14

Enumerable#lazy から値を取り出す場合...

irb(main):010:0> lazy = (1..Float::INFINITY).lazy
=> #<Enumerator::Lazy: 1..Infinity>
irb(main):011:0> lazy.take(3)
=> #<Enumerator::Lazy: #<Enumerator::Lazy: 1..Infinity>:take(3)>
irb(main):012:0> lazy.take(3).force
=> [1, 2, 3]
irb(main):013:0> lazy.first(3)
=> [1, 2, 3]
  • Enumerator::Lazy#take を利用すると, 配列ではなく Enumerator::Lazy を返すので, Enumerator::Lazy#force を合わせて利用する
  • Enumerable#first を利用すると, 配列として値を取得出来る

socket

socket ライブラリに含まれるクラス.

  • UDPSocket
  • TCPSocket
  • BasicSocket

階層で表すと以下のようになる.

socket
└── BasicSocket
    └── IPSocket
        ├── TCPSocket
        │   ├── SOCKSSocket
        │   └── TCPServer
        └── UDPSocket

self

self が何を参照しているのか.

class A
  $a = self
  def hoge
    $b = self
  end
end
a = A.new
print A == $a, A.new == $b

以下, irb にて確認.

irb(main):001:0> class A
irb(main):002:1>   $a = self
irb(main):003:1>   def hoge
irb(main):004:2>     $b = self
irb(main):005:2>   end
irb(main):006:1> end
=> :hoge
irb(main):007:0> a = A.new
=> #<A:0x0055c2177251a8>
irb(main):008:0> print A == $a, A.new == $b
truefalse=> nil
irb(main):009:0> print A == $a, A.new.hoge == $b
truetrue=> nil
irb(main):010:0> p $a
A
=> A
irb(main):011:0> p $b
#<A:0x0055c2176f9df0>
=> #<A:0x0055c2176f9df0>
  • クラス定義中の self は, そのクラスのオブジェクトである
  • インスタンスメソッド中の self は, そのクラスのオブジェクトである
  • $a にはクラス A が代入され, $b は, hoge が実行されなければ値は代入されない

今日の AWS ~ リージョンとアベイラビリティゾーン ~

リージョン

  • 2016 年 7 月現在, 世界中に 13 ヶ所のリージョン
  • GovCloud と北京リージョンについては通常のユーザーは利用出来ない

アベイラビリティゾーン

サービス

  • リージョン毎に管理されるリージョンサービス
    • S3
    • DynamoDB
    • SQS
  • AZ 毎に管理されるサービス
    • EC2
    • RDS
    • ELB
    • ElastiCache
  • どのリージョンからでも利用可能なグローバルサービス
    • IAM
    • Route53
    • CloudFront

フムフム.

JRuby で JVM の起動時間を短縮出来ないか調査した (Nailgun を試した)

tl;dr

inokara.hateblo.jp

前回の記事で, JRubyスクリプトrspec を実行する際に JVM の起動時間の遅さがすごく気になっていたので, これを短縮する方法について調べたら Nailgun というオプションを使うと良さそうということで試したメモ.

本記事で試す環境は, 前回の記事と同様に以下のような環境を利用する.

$ java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)
$ jruby --version
jruby 9.2.0.0 (2.5.0) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 25.171-b11 on 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11 +jit [linux-x86_64]

Nailgun とは

github.com

上記のドキュメントより引用.

In JRuby 1.3, we officially shipped support for Nailgun. Nailgun is a small library and client-side tool that reuses a single JVM for multiple invocations. With Nailgun, small JRuby command-line invocations can be orders of magnitude faster.

  • 単一の JVM を複数の呼び出しに再利用する小さなライブラリとクライアントサイドのツール
  • Nailgun を利用すると, 小さな JRubyコマンドライン呼び出しを数桁速くすることが出来る

Nailgun を利用するには, JRuby--ng-server オプションで起動しておいて, 別の端末の JRuby--ng オプションを付けて起動する.

# Nailgun サーバーを起動
$ jruby --ng-server &

# 別の端末で Nailgun モードでスクリプトを実行
$ jruby -S --ng sample.rb

試す

Hello World

以下のようなコードを用した.

p 'hello world'

これを hello_world.rb として保存して, Nailgun を利用した場合と利用しない場合で実行時間の変化を確認.

# Nailgun を使わない x 3 回
$ time jruby -S hello_world.rb 
"hello world"

real    0m2.414s
user    0m6.140s
sys     0m0.168s
$ time jruby -S hello_world.rb 
"hello world"

real    0m2.524s
user    0m6.624s
sys     0m0.184s
$ time jruby -S hello_world.rb 
"hello world"

real    0m2.441s
user    0m6.268s
sys     0m0.152s

# Nailgun を使う x 3 回
$ time jruby -S --ng hello_world.rb 

real    0m3.921s
user    0m0.032s
sys     0m0.016s
$ time jruby -S --ng hello_world.rb 

real    0m0.851s
user    0m0.016s
sys     0m0.012s
$ time jruby -S --ng hello_world.rb 

real    0m0.763s
user    0m0.016s
sys     0m0.028s

Nailgun を使わない場合, たかだか Hello world で 3 秒くらい掛かってしまう. Nailgun を利用すると, 初回は Nailgun を利用しない場合と殆ど変わらないが, 2 回目以降は 3 分の 1 程の時間で処理が完了している. 尚, Nailgun を利用した場合, Hello world が出力されていないが, これは Nailgun サーバーを起動した端末側で出力されている.

minitest

以下のような, 超簡単なテストコードを実行させてみる.

require 'minitest/autorun'

class FooTest < Minitest::Test
  def test_foo
    assert_equal 'foo', 'foo'
  end
end

これを minitest.rb として保存し, Nailgun を利用した場合と利用しない場合で実行時間の変化を確認.

# Nailgun を使わない x 3 回
$ time jruby -S minitest.rb 
Run options: --seed 58096

# Running:

.

Finished in 0.026389s, 37.8950 runs/s, 37.8950 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

real    0m3.359s
user    0m9.492s
sys     0m0.196s
$ time jruby -S minitest.rb 
Run options: --seed 9728

# Running:

.

Finished in 0.032048s, 31.2030 runs/s, 31.2030 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

real    0m3.523s
user    0m10.096s
sys     0m0.220s

$ time jruby -S minitest.rb 
Run options: --seed 24004

# Running:

.

Finished in 0.033907s, 29.4925 runs/s, 29.4925 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

real    0m3.368s
user    0m9.760s
sys     0m0.208s

# Nailgun を使う x 3 回
$ time jruby -S --ng minitest.rb 

real    0m1.699s
user    0m0.020s
sys     0m0.020s
$ time jruby -S --ng minitest.rb 

real    0m1.430s
user    0m0.024s
sys     0m0.016s
$ time jruby -S --ng minitest.rb 

real    0m1.113s
user    0m0.028s
sys     0m0.020s

RSpec

以下のような RSpec で実行可能なテストコードを書いてみた.

require 'rspec/expectations'

RSpec::Matchers.define :have_word do |expected|
  match do |actual|
    actual.include?(expected)
  end
end

RSpec.describe 'foo-bar-bar' do
  it { should have_word('foo') }
end

これを rspec.rb として保存し, 動作確認してみる.

# Nailgun を使わない x 3 回
$ time jruby -S rspec rspec.rb
... 略 ...
real    0m5.050s
user    0m14.120s
sys     0m0.248s
$ time jruby -S rspec rspec.rb
... 略 ...
real    0m4.853s
user    0m13.624s
sys     0m0.284s
$ time jruby -S rspec rspec.rb
... 略 ...
real    0m5.101s
user    0m14.404s
sys     0m0.240s

# Nailgun を使う x 3 回
$ time jruby -S --ng rspec rspec.rb
real    0m1.510s
user    0m0.012s
sys     0m0.020s
$ time jruby -S --ng rspec rspec.rb
real    0m1.795s
user    0m0.012s
sys     0m0.004s
$ time jruby -S --ng rspec rspec.rb
real    0m2.585s
user    0m0.036s
sys     0m0.020s

ぱっと見た感じだと, 何れの場合にも Nailgun を利用した方が圧倒的に処理時間は速いように見える.

以上

すごくイイこと尽くめに感じる Nailgun だが, ドキュメントには以下のように書かれている.

Nailgun seems like a magic bullet, but unfortunately it does little to help certain common cases like booting RubyGems or starting up Rails (such as when running tests). It also can't help cases where you are causing lots of sub-rubies to be launched, and if you have long-running commands the usual Control-C may not be able to shut them down on the server. Your best bet is to give it a try and let us know if it helps.

Nailgun は魔法の弾丸じゃないし, gem の起動やテストの実行時など, Railsの起動などの一般的なケースはほとんど役に立たないとあるので, 実際に利用する場合には注意が必要.

参考

github.com

tagomoris.hatenablog.com

ありがとうございました.

2018 年 08 月 05 日 (日)

ジョギング

  • 香椎浜 x 2 周
  • 引き続き, 徹底的に熱い (暑いではなく, もはや熱い)

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

熱中症気味

油断して 10 時過ぎに走りに行ってしまった為, その後, ひどい頭痛と倦怠感があってダラダラ過ごしていた.

今日のるびぃ ~ 例外 ~

例外の理解がイマイチなので, パターン別に挙動を確認する. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

パターン 1

# パターン 1-1 (StandardError を継承している場合)
class MyError1 < StandardError; end

begin
  raise MyError1
rescue => e
  puts "StandardError!!"
end
puts "End"

# irb での出力結果
... 略 ...
StandardError!!
=> nil
irb(main):008:0> puts "End"
End
=> nil

# パターン 1-2 (StandardError を継承していない場合)
class MyError1; end

begin
  raise MyError1
rescue StandardError => e
  puts "StandardError!!"
end
puts "End"

# irb での出力結果
StandardError!!
=> nil
irb(main):008:0> puts "End"
End
=> nil
  • 任意のクラス (例: MyError1) が StandardError を継承している場合には, StandardError で例外が捕捉される
  • StandardError を明示的に継承していない場合でも, StandardError で例外が捕捉される

パターン 2

# パターン 2
class MyError1 < StandardError; end

begin
  raise MyError1
rescue MyError1 => e
  puts "MyError1"
rescue StandardError => e
  puts "StandardError!!"
end
puts "End"

# irb での出力結果
... 略 ...
MyError1
=> nil
irb(main):010:0> puts "End"
End
=> nil
  • 例外オブジェクトのクラスは MyError1 なので, 7 行目の MyError1 で rescue される
  • StandardError を継承している場合でも, 例外オブジェクトのクラス名で rescue されていれば, そちらの方が優先される

パターン 3

# パターン 3
class MyError1 < StandardError; end
class MyError2 < MyError1; end

begin
  raise MyError1
rescue MyError2 => e
  puts "MyError1"
rescue StandardError => e
  puts "StandardError!!"
end
puts "End"

# irb での出力結果
... 略 ...
StandardError!!
=> nil
irb(main):011:0> puts "End"
End
=> nil
  • 例外オブジェクトのクラスは MyError1 なので, MyError2 では rescue 出来ずに, その次の StandardError で rescue される

パターン 4

# パターン 4
class MyError1 < StandardError; end
class MyError2 < MyError1; end

begin
  raise MyError2
rescue MyError1 => e
  puts "MyError1"
rescue StandardError => e
  puts "StandardError!!"
end
puts "End"

# irb での出力結果
... 略 ...
MyError1
=> nil
irb(main):011:0> puts "End"
End
=> nil
  • 例外オブジェクトのクラスは MyError2 だが, MyError2 は MyError1 を継承している為, MyError1 でも rescue される

パターン 5

# パターン 5
class Error1 < StandardError; end
class Error2 < Error1; end
begin
  raise Error2
rescue Error1 => ex
  puts ex.class
end

# irb での出力結果
... 略 ...
Error2
=> nil
  • 例外オブジェクトのクラスは MyError2 だが, MyError2 は MyError1 を継承している為, MyError1 でも rescue される
  • また ex.class で例外オブジェクトのクラス名を取得している

今日の AWS ~ S3 ~

ストレージクラス

  • スタンダード (耐久性 99.999999999% で, リージョン内の 3 箇所のデータセンターに保存)
  • 冗長化 (耐久性 99.99% でコストはスタンダードよりも低い)
  • 低頻度アクセス

S3 の整合性について

  • S3 は格納したデータを複数のデータセンターに複製することで高いデータ耐久性を実現している
  • 但し, 書き込み, 更新, 削除時のデータの整合性について注意が必要となる

以下, オブジェクトに対するアクション毎にざっくりと整理.

オブジェクトに対するアクション 整合性の種類 メモ
新規書き込み 書き込み後の読み取り整合性 アップロード直後は, オブジェクトにアクセス出来ないことがある
上書き書き込み 結果整合性 上書き後, オブジェクトにアクセスしても古いデータが返されることがある
削除 結果整合性 削除後, 削除したはずのデータにアクセス出来ることがある

フムフム.

JRuby で aws-sdk-ruby を動かす

tl;dr

たまたま aws-sdk-ruby に含まれている .travis.yml を見ていたら, 以下のように JRuby 環境でもテストを行っているようなので, 手元の環境でも JRuby 環境下で aws-sdk-ruby を試してみたメモ.

... 略 ...
rvm:
  - 1.9.3
  - 2.0.0
  - 2.1
  - 2.2
  - 2.3
  - 2.4
  - 2.5
  - jruby-9.1.16.0
... 略 ...

特にギョームで JRuby を使う予定は無い為, 本当にあくまでも興味本位として動かしてみた系のお話. 特に深堀はせずにとりあえず動いていることが確認出来れば OK という感じで進める.

尚, お試しの環境は以下の通り.

$ java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)
$ jruby --version
jruby 9.2.0.0 (2.5.0) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 25.171-b11 on 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11 +jit [linux-x86_64]

JRuby の導入

導入方法は幾つかあるが, 今回は rbenv を使って導入した.

$ rbenv install jruby-9.2.0.0
$ rbenv local jruby-9.2.0.0

これだけ.

aws-sdk-ruby の導入

とりあえず, aws-sdk-s3 のみを導入してみる.

$ jruby -S gem install aws-sdk-s3 --no-ri --no-rdoc -V

これだけ. 画面への出力については, 特に CRuby との違いはなく, 何の問題もなくインストールが完了する.

ちなみに, -S オプションは以下の通り.

-S                look for the script in bin or using PATH environment variable

サンプル

aws-sdk-s3 を使って, S3 バケットの一覧を取得するサンプルを以下のように作成する.

require 'aws-sdk-s3'

s3 = Aws::S3::Client.new(
                         region:'ap-northeast-1',
                         profile:'default',
                        )

p s3.list_buckets.buckets.map(&:name)

これを sample.rb というファイル名で保存して, 以下のように実行する.

$ jruby sample.rb

まず JVM が起動する為, CRuby で実行するよりも実行時間を要するが, 以下のように無事にバケットの一覧を取得出来た.

$ jruby sample.rb 
["sample1", "sample2", "sample3"]

おおー, いい感じ.

awspec は動くのか

せっかくなので

awspecJRuby 上で動作するのか試してみたい. 尚, あくまでもお試しである為, 完全に動作を保証するものではない. ご注意下さいまし.

awspec の導入

先ほどの aws-sdk-s3 導入と同様に, 以下のように awspec を導入する.

$ jruby -S gem install awspec --no-ri --no-rdoc -V

特に問題無くインストールが完了した.

awspec init

awspec に必要なディレクトリ等を作成する.

$ jruby -S awspec init

以下のように出力され, 必要なディレクトリ等が作成される. やはり, CRuby で実行するよりも時間はかかる.

$ jruby -S awspec init
 + spec/
 + spec/spec_helper.rb
 + Rakefile
 + spec/.gitignore
 + .rspec

テストを実行する

以下のような spec を書いた. S3 バケットが存在しているかどうかをテストする.

require 'spec_helper'

describe s3_bucket('my-bucket') do
  it { should exist }
end

以下のようにテストを実行する.

$ jruby -S rspec spec

以下のように出力されて, テストが動いていることを確認出来た.

# 存在しないバケットでテスト
$ jruby -S rspec spec

s3_bucket 'my-bucket'
  should exist (FAILED - 1)

Failures:

  1) s3_bucket 'my-bucket' should exist
     Failure/Error: it { should exist }
       expected s3_bucket 'my-bucket' to exist
     # ./spec/s3_spec.rb:4:in `block in (root)'

Finished in 2.3 seconds (files took 10.68 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/s3_spec.rb:4 # s3_bucket 'my-bucket' should exist

# 存在しているバケットでテスト
$ jruby -S rspec spec

s3_bucket 'sample1'
  should exist

Finished in 2.11 seconds (files took 10.69 seconds to load)
1 example, 0 failures

いい感じですな.

注意

以下の issue に言及されている通り, awspec は JRuby 上での動作は正式にはサポートされていない.

github.com

また, JVM の起動の遅さに引きづられてしまい, 簡単なテストでも 10 秒くらい掛かってしまうので, 現時点では実用的ではないと思われる.

以上

興味本位で試してみた系でした. JRuby だからって, あんまり構える必要は無いんだなって思った.

2018 年 08 月 04 日 (土)

ジョギング

  • 香椎浜 x 2 周
  • 徹底的に熱い (暑いではなく, もはや熱い)

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

カラオケトレーニング

週末恒例の奥さんとのカラオケトレーニング. 今日は 2 時間. 奥さんの調子が悪そうだったけど, イキイキと楽しく歌っている姿を見ると嬉しい.

今日のるびぃ ~ ひさびさに IT トレメ (1) ~

irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

IT トレメ はちょっと易しい問題が並んでいるけど, 問題に慣れる, 基礎を叩き込むという意味で活用している. 全問正解が前提だが, 問題を解く上で疑問に感じた問題を掘り下げる.

Q6 例外

以下のコードを実行すると何が表示されるか.

class Error1 < StandardError; end
class Error2 < Error1; end
begin
  raise Error2
rescue Error1 => ex
  puts ex.class
end

解答は...

Error2 が出力される

以下, irb にて確認.

irb(main):001:0> class Error1 < StandardError; end
=> nil
irb(main):002:0> class Error2 < Error1; end
=> nil
irb(main):003:0> begin
irb(main):004:1*   raise Error2
irb(main):005:1> rescue Error1 => ex
irb(main):006:1>   puts ex.class
irb(main):007:1> end
Error2
=> nil

以下, 解説.

  • rescue 節で捕捉できる例外は, 指定した例外クラスと, そのクラスのサブクラス
  • 設問では, rescue 対象は Error1 と指定しているが, サブクラスの Error2 が raise されている為, Error2 の例外も捕捉することが出来る

Q41

以下のそれぞれのコードを実行した場合に何が出力されるか.

[コード1] 
class Foo 
 Const = "foo" 
  def foo 
  puts Const 
 end 
end 
Foo.new.foo 

[コード2] 
module M 
 def foo 
  puts Const 
 end 
end 
class Foo 
 Const = "foo" 
  include M 
end 
Foo.new.foo

以下, 解答.

foo
例外が発生する (NameError) 

以下, irb にて確認.

# コード 2 について
irb(main):001:0> module M
irb(main):002:1>   def foo
irb(main):003:2>     puts Const
irb(main):004:2>   end
irb(main):005:1> end
=> :foo
irb(main):006:0> class Foo
irb(main):007:1>   Const = 'Foo'
irb(main):008:1>   include M
irb(main):009:1> end
=> Foo
irb(main):010:0> Foo.new.foo
NameError: uninitialized constant M::Const
  • module M 内に定数 Const が定義されていない為, NameError が発生する

Q42

以下のそれぞれのコードを実行した場合に何が出力されるか.

[コード1] 
class Foo 
  def foo 
    puts "foo" 
  end 
end 
class Bar < Foo 
  def foo 
    puts "bar" 
  end 
end 
class Bar 
  undef_method :foo 
end 
Bar.new.foo 

[コード2] 
class Foo 
  def foo 
    puts "foo" 
  end 
end 
class Bar < Foo 
  def foo 
    puts "bar" 
  end 
end 
class Bar 
  remove_method :foo 
end 
Bar.new.foo

以下, 解答.

NoMethodError
foo

以下, irb にて確認.

[コード 1]
... 略 ...
irb(main):014:0> Bar.new.foo 
NoMethodError: undefined method `foo' for #<Bar:0x00556348e66788>

[コード 2]
... 略 ...
irb(main):014:0> Bar.new.foo
foo
=> nil

以下, 解説.

  • remove_method しても, スーパークラスに同名クラスがある場合にはそのメソッドを呼び出すことが出来る

Q49

以下のコードを実行すると何が表示されるか.

[コード] 
class Bar 
  def foo 
    puts "barbarbar" 
  end 
end 
class Foo < Bar 
  def initialize(obj) 
    obj.foo 
  end 
  def foo 
    puts "foofoofoo" 
  end 
end 
Foo.new(Foo.new(Bar.new)) 

以下, 解答.

barbarbar foofoofoo

以下, irb にて確認.

... 略 ...
irb(main):014:0> Foo.new(Bar.new)
barbarbar
=> #<Foo:0x0056012a830230>
irb(main):015:0> f = Foo.new(Bar.new)
barbarbar
=> #<Foo:0x0056012a801520>
irb(main):016:0> Foo.new(f)
foofoofoo
=> #<Foo:0x0056012a7fd8f8>
irb(main):017:0> Foo.new(Foo.new(Bar.new))
barbarbar
foofoofoo
=> #<Foo:0x0056012a641a50>

フムフム.