RubyのHashで要素数を取得するヘ(^o^)ノ

Hashで要素の数を取得してみる

Hash#lengthとHash#size

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.length #=> 3
favorites_language.size   #=> 3

Enumerable#count

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.count #=> 3

では、Valueが'Ruby'である要素の数を取得してみる

Hash#lengthとHash#size

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.select{|k, v| v == 'Ruby'}.size #=> 2

Enumerable#count{|obj| ...}

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.count{|key, v| v == 'Ruby'} #=> 2

そう!countにはブロックを渡せるのだー(今までマジで知らんかった...

もう少しおしゃれにしてみよう

Enumerable#count(item)

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.values.count('Ruby') #=> 2

まだまだ知らんこといっぱいですわー

がんばろっと

Happy Hacking٩( ‘ω’ )و

第65回 Ruby関西 勉強会に参加したよヘ(^o^)ノ

第65回 Ruby関西 勉強会に参加し、発表してきました。

発表内容はRails4.2の新機能について。

4.2がリリースされてから2ヶ月が経ちますが、ActiveJob中心に紹介させてもらいました。

発表中にデモする時があると思います

スライド見ながらタイプするの大変ですよねー( ̄▽ ̄;)

そんな時はtmuxですよ!

  • tmuxを起動

f:id:murajun1978:20150222191156p:plain

  • 新しいターミナルから、起動済みtmuxへアクセス
$ tmux attach -t 0
  • 普通に操作する

f:id:murajun1978:20150222192232g:plain

これで発表中のデモも楽ちんですねーヘ(^o^)ノ

Happy Hacking٩( ‘ω’ )و


みなさんの発表内容

Ruby 2.0 以降の変更をふりかえる

@sixeightさん


RubyでBCCWJを弄ぶ

@pico1aさん


Wakayama.rbボードの紹介

@momoongaさん


Rubyコミュニティx企業

@takamiya_amsさん


Medaka.rb活動概要

@matsushin11さん


Gemをコードリーディングしてみよう!

@taiyopさん


Rails見える化 開発(API編)

@ogomさん


Treasure DataでのRubyの利用

@repeatedlyさん


追記
  • 2014/02/27 @takamiya_amsさんのスライド追加

Gitのコンフリクト時にmergetoolで確認してマージするヘ(^o^)ノ

Gitでコンフリクトしたときに、GUIIDEだと差分が確認しやすいみたい。

でも、僕はVimなの...

そこでmergetoolですよ!

実際にやってみよう。

# hello.rb
class Hello
  def say
    "Hello"
  end
end

コミットして、ブランチを切ります。

$ git init
$ git add .
$ git commit -m 'first commit'
$ git checkout -b add_name

修正してみます。

# hello.rb
class Hello
  def say(name)
    "Hello #{name}"
  end
end

コミットして、masterブランチへ

$ git add .
$ git commit -m 'add name'
$ git checkout master

わざとコンフリクトさせてみましょう。

マージする前に、masterブランチのファイルを修正します。

# hello.rb
class Hello
  def say
    "Hello!"
  end
end

コミットして、マージします。

$ git add .
$ git commit -m 'add exclamation mark'
$ git merge add_name

コンフリクトしました!

Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.

コマンドを実行します。

$ git mergetool
  • 左はマージする前の状態
  • 右はマージしたいところ
  • 中央は右のマージしたいところが作られる前の状態
  • 下はマージして保存するファイル

f:id:murajun1978:20150211004426p:plain

どうですか?

今のmasterブランチの状態と、マージ前の状態とマージしようとしているファイルの状態が

わかりやすいですよね?

masterブランチには'!'が、add_nameブランチにはnameが追加されています。

ファイルを編集して、保存します。

# hello.rb
class Hello
  def say(name)
    "Hello #{name}!"
  end
end

コンフリクトしたときのファイルはhello.rb.origで保存されています。

必要なければ削除して、コミットしましょう。

$ git commit -m 'merge add_name'

これで、コンフリクトのマージ作業が安全に行えそうですね。

Happy Hacking٩( ‘ω’ )و

d(゚Д゚ )☆スペシャルサンクス☆( ゚Д゚)b

Gitコンフリクト解消ガイド(git mergetoolの使い方)

神戸.rb Meetup #12に参加したよーヘ(^o^)ノ

神戸.rb Meetup #12に参加しました。

僕はKonachaについて調べてました。

会社でRailsJavaScriptをええー感じにテストしたい!ってことなので

# Gemfile
group :test, :development do
  gem 'konacha'
  gem 'selenium-webdriverd'
end

デフォルトのdriverはseleniumです。

実際にテストを書いてみる

# app/assets/javascripts/hello.js.coffee
class @Hello
  @say_hello: (name) ->
    "Hello #{name}!"
# rspec/javascripts/hello_spec.js.coffee

#= require hello

describe 'Hello#say_hello', ->
  it "returns 'Hello murajun1978!'", ->
    expect(Hello.say_hello('murajun1978')).to.eql("Hello murajun1978!")

テストを実行する

$ bundle exec rake konacha:run
.

Finished in 0.00 seconds
1 examples, 0 failed, 0 pending

テスト通ったねー

んじゃ、headlessでテストしてみる

# Gemfile
gem 'poltergeist'
# gem 'selenium-webdriver'
# config/initializers/konacha.rb
Konacha.configure do |config|
  require 'capybara/poltergeist'
  config.driver = :poltergeist
end if defined?(Konacha)

headlessでテストできたねーヘ(^o^)ノ

Happy Hacking٩( ‘ω’ )و


追記
  • 2015/02/23
    • hello_spec.js.coffeeでrequireしていなかったので追記
    • config.driverの指定が間違ってたので修正

神戸.rb Meetup #11 に参加したよヘ(^o^)ノ

Kobe.rbに参加してきたよヘ(^o^)ノ

今日のおやつ!! f:id:murajun1978:20150121003951j:plain f:id:murajun1978:20150121003947j:plain photo by @spring_aki

おいしかった♪

今日、僕が調べてたのはActiveDecorator + Capybara + RSpecです。

ActiveDecoratorでhelperを良く使いますよねー

例えばこんなの...

def full_name
  content_tag :td do
    "#{first_name} #{last_name}"
  end
end

Decoratorが自動生成するRSpecはこちら

describe UserDecorator
  let(:user) { User.new.extend UserDecorator }
  subject { user }
  it { should be_a User }
  [...]
end

毎回extendするのもアレなので、ActiveDecorator::RSpecを使います

# Gemfile
gem 'active_decorator-rspec'

# spec/decorator/user_decorator_spec.rb
describe UserDecorator
  # FactoryGirlでテストデータ作成
  let(:user) { build(:user) }
  subject { decorate user }
  it { should be_a User }
  [...]
end

いい感じですねー

キモのfull_nameメソッドをCapybaraでテストしてみましょう

describe UserDecorator
  [..]
  it 'has a tr tag and full_name' do
    expect(subject.name).to have_content(:td, "#{user.first_name} #{user.last_name}")
  end
end

実行すると怒られます。。。

undefined method 'content_tag' for ...

RSpecがhelperメソッドを認識してないもよう。

type: :heler or type: :viewを指定すればhelperメソッドが認識されますが、 こんどはCapybaraにおこられます( ̄▽ ̄;)

have_contentはCapybara::RSpecMatchersで定義されてるのでincludeしてみます

describe UserDecorator
  include Capybara::RSpecMatchers
  let(:user) { build(:user) }
  subject { decorate user }
  it { should be_a User }
  
  it 'has a tr tag' do
    expect(subject.name).to have_content(:td)
  end
end

これでテストを実行すればパスしますが、毎回includeはアレなのでrails_helperに追記

# spec/rails_helper.rb
RSpec.configure do |config|
  config.include Capybara::RSpecMatchers, type: :decorator
end
describe UserDecorator
  let(:user) { build(:user) }
  subject { decorate user }
  it { should be_a User }
  
  it 'has a tr tag', type: :decorator do
    expect(subject.name).to have_content(:td, "#{user.first_name} #{user.last_name}")
  end
end

これでCapybaraを使ってテストできますねー

Happy Hacking٩( ‘ω’ )و

Rails - ActiveDecoratorのコード読んでみたヘ(^o^)ノ

いつもお世話になります。ActiveDecoratorさま。

@izumin5210さんの「ActiveDecorator読んでみたら超勉強になった」を読んで、そういやコードあんま見てなかったので読んでみた

なるほど編

コードよむ編

# lib/active_decorator/monkey/abstract_controller/rendering.rb
module AbstractController
  module Rendering
    # to_aメソッドのエイリアス↓
    def view_assigns_with_decorator 
      # 既存のto_aメソッドをコール
      hash = view_assigns_without_decorator

      # メソッドを拡張
      hash.values.each do |v|
        ActiveDecorator::Decorator.instance.decorate v
      end
      hash
    end
    
    # :view_assigns => :view_assigns_with_decorator
    # :view_assigns_without_decorator => :view_assigns
    alias_method_chain :view_assigns, :decorator
  end
end

view_assignsは、Controllerで取得したインスタンスなんかが格納されたHashを返しますよー

こんな感じ↓

f:id:murajun1978:20150114225602p:plain

postsはActiveRecord::Relationです(Post.allしたやつ)

testはインスタンス変数に文字列をいれてみた

このHashをActiveDecorator::Decorator

# lib/active_decorator/decorator.rb
module ActiveDecorator
  class Decorator
    include Singleton

    def initialize
      @@decorators = {}
    end

    def decorate(obj)
      [...]
    end
    [...]
  end
end

singletonをMix-inしてるので、ActiveDecorator::Decorator.instance.decorateで呼び出してますよ

decorateメソッド
if obj.is_a?(Array)
  # *2でArrayが引数となるのでここ
  # Arrayの要素(ModelClass)を引数として自身を呼び出してる *3
  obj.each do |r|
    decorate r
  end
elsif defined?(ActiveRecord) && obj.is_a?(ActiveRecord::Relation) && !obj.respond_to?(:to_a_with_decorator)
  # ActiveRecord::Relationならクラスを再オープンしてメソッド定義してる *1
  class << obj
    def to_a_with_decorator
      to_a_without_decorator.tap do |arr|
        # Arrayを引数として自身を呼び出してる *2
        ActiveDecorator::Decorator.instance.decorate arr
      end
    end
    alias_method_chain :to_a, :decorator
  end
else
  # *3で引数がmodelクラスとなるのでここ(ActiveRecord::Relation、Array以外もここ)
  # decoratorのクラス取得してる
  d = decorator_for obj.class
  return obj unless d
  # PostDecoratorモジュールに属してなければextendしてる
  obj.extend d unless obj.is_a? d  
end
decorator_forメソッド
private
def decorator_for(model_class)
  return @@decorators[model_class] if @@decorators.has_key? model_class

  decorator_name = "#{model_class.name}Decorator"
  d = decorator_name.constantize
  unless Class === d
    d.send :include, ActiveDecorator::Helpers
    @@decorators[model_class] = d
  else
    @@decorators[model_class] = nil
  end
rescue NameError
  @@decorators[model_class] = nil
end

ViewContextをごっそり

# lib/active_decorator/view_context.rb
module Filter
  extend ActiveSupport::Concern

  included do
    before_filter do |controller|
      ActiveDecorator::ViewContext.current = controller.view_context
    end
  end
end

helperの拡張

# lib/active_decorator/helpers.rb
module Helpers
  def method_missing(method, *args, &block)
    super
  #TODO need to make sure who raised the error?
  rescue NoMethodError, NameError => original_error
    begin
      # helperでmethod_missingならActiveDecorator::ViewContextから(なければoriginal_errorの例外発生
      ActiveDecorator::ViewContext.current.send method, *args, &block
    rescue NoMethodError, NameError
      raise original_error
    end
  end
end

ViewContextをごっそりとってるから、flashとかもdecoratorで使えるよー

ActiveDecorator::ViewContext.current.flash 
=> #<ActionDispatch::Flash::FlashHash:0x007fda40e27d78 @discard=#<Set: {}>, @flashes={"error"=>"test error"}, @now=nil>
ActiveDecorator::ViewContext.current.flash[:error]
=> "test error"

# app/decorators/post_decorator.rb
module PostDecorator
  def error_flash
    flash[:error]
  end
end

ActiveDecoratorだと読みやすくて勉強にも良いかと思います♪

Happy Hacking٩( ‘ω’ )و

d(゚Д゚ )☆スペシャルサンクス☆( ゚Д゚)b

神戸.rb Meetup #10に行ってきたよヘ(^o^)ノ

今日は神戸.rb Meetup #10に行ってきた。

仕事が押して1時間ほど遅れてしまったけど。。。( ̄▽ ̄;)

みんながそれぞれ興味あることをワイワイ話したり、もくもくしたりと良い感じです。

おやつもあるっ!!!

僕はcocoon(こくーん?)ってgemを使ってみました。

ユーザーストリーにタスクをポンポン追加していくときに使うー

使い方はとても簡単

//= require cocoon
  • fields_forを使って子モデルを追加したりできるようにする
  %h3 Tasks
  #tasks
  .field
    = f.fields_for :tasks do |task|
      = render 'task_fields', f: task
  .links
    = link_to_add_association f, :tasks do
      = icon('plus-square fa-2x')

  .actions
    = f.submit 'Save'

# _task_fields.html.haml
.nested-fields
  .field
    = f.label :name
    = f.text_field :name
    = f.label :description
    = f.text_field :description
    = link_to_remove_association  f do
      = icon('times fa-2x')

10分くらいでできたサンプルがコレ

f:id:murajun1978:20150107012455g:plain

そして懇親会♪

ゆりえちゃんのお話もできたしー.。oO(かわいい)

みなさんお疲れ様でしたヘ(^o^)ノ