雑にRefinementsが使えるようにしてみた

経緯

最近、「Rubyにこういうのあったら便利かなぁ」と思ったメソッドをrstdというgemに追加して個人プロジェクトとかで使えるようにするのがマイブームになっています。

github.com

で、色々実装している時に、サクッとRefinementsが使えないだろうかと思い、実装してみた記事になります。

やりたかったこと

以下のようなコードで特定のクラス内などでサクッとRefinementsが使いたかった。

class A
    using refine_method(Integer, :inc, ->() {self + 1})

    def inc
      puts 41.inc
    end
end

A.new.inc
# => 42  

実装

で、実際の実装は以下のような感じです。

module RefineKernel
  refine Kernel do
    def refine_method(klass, method_id, expr)
      Module.new{
        refine klass do
          define_method method_id.to_sym, expr
        end
      }
    end
  end
end

using RefineKernel

class A
    using refine_method(Integer, :inc, ->() {self + 1})

    def inc
      puts 41.inc
    end
end

A.new.inc
# => 42  

やってること

module RefineKernel
  # Kernel で refine_method が使えるようにする
  refine Kernel do
    def refine_method(klass, method_id, expr)
      Module.new{
        refine klass do
          define_method method_id.to_sym, expr
        end
      }
    end
  end
end

Kernelrefine_method というメソッドが使えるようにしています。
またrefine_method は引数として klassmethod_idexprを受け取ります。

klassはRefinementsでメソッドを追加したいクラスを引数として渡しており、method_id が追加するメソッド名、expr がメソッドの実装となっています。

あとはusing RefineKernelすれば、以下のようにRefinementsを使ってメソッドを追加し、利用することができます。

using RefineKernel

using refine_method(Integer, :inc, ->() {self + 1})

p 41.inc
# => 42

ちなみに以下のような感じでも動作するので意外と便利かも……?

using refine_method(Array, :pow, ->(num = 2){ self.map{|v| v ** num }})

ary = [1, 2, 3]

puts ary.pow
# => [1, 4, 9]

puts ary.pow(3)
# => 1, 8, 27

using refine_method(Object, :xbox, ->(title = "HALO", *args){
  puts title if args.size == 0
  args.each do |arg|
    puts "#{title} #{arg}"
  end
})

obj = Object.new

obj.xbox
# => HALO

obj.xbox("HALO", "CE", 2, 3)
# => HALO CE
# => HALO 2
# => HALO 3

obj.xbox("Devil May Cry", "", "2", "4", "5")
# => Devil May Cry 
# => Devil May Cry 2
# => Devil May Cry 4
# => Devil May Cry 5

ただ、一度に一つのメソッドしか定義できないのが不満かな。 そこらへんはいい感じにHashオブジェクト内にSymbolとProcを格納してmapとかで回せばいいのかもしれないけど。

実際のPRとか

github.com

github.com

Cognitoで複数のコールバック先を指定して別々のページに遷移できるようにしてみた

注意

仕事の関係でCognitoのに複数のコールバック先を指定できないか試したときの覚書です。

背景

とあるWebサービスでCognitoを使ってソーシャルログインで自動的にアカウントを作成できる画面を作っていました。 で、仕様変更でアカウント登録画面が複数になり、アカウント登録の画面それぞれにうまいことコールバックさせる必要が出てきた。

やったこと

Cognito側に複数のコールバック先を先に指定し、それぞれの登録画面用のソーシャルログインの処理を以下のように切り出した。

    Auth.configure({
      Auth: constAuth,
      oauth: {
        ...constOauth,
        redirectSignIn: process.env.REACT_APP_CALLLBACK_URL,
      },
    });

const socialLogin = async (provider: CognitoHostedUIIdentityProvider) => {
    await Auth.federatedSignIn({
      provider,
    });
  };

const anotherSocialLogin = async (provider: CognitoHostedUIIdentityProvider) => {
    Auth.configure({
      Auth: constAuth,
      oauth: {
        ...constOauth,
        redirectSignIn: process.env.REACT_APP_ANOTHER_CALL_BACK_URL,
      },
    });
    await Auth.federatedSignIn({
      provider,
    });
  };

上記のコードでは、それぞれソーシャルログインでコールバック先を切り替えている。

で、あとはコールバック先でソーシャルログイン時に作成されたアカウント情報とかを受け取って、それぞれの画面に遷移させればOK。 その辺はreact-touterhistoryとか使って前のURLをよしなに比較すればOKな感じです。

参考

ref: Pass "redirectUri" as a parameter to Auth.federatedSignIn #4326

浜田市の防災情報をLINEで通知してくれるBotを作った。

はじめに

浜田市の若者会議のメンバーの方から「浜田市の防災情報を通知してくれるアプリとかあるとうれしい」という話をいただいたので、実際に作ってみた話です。

 

作ったもの

github.com

 

実際にLINEで防災情報を通知してくれるBotはこちらのQRコードを読み込むか「@689nsohm」で友達追加していただければOKです。

f:id:gamelinks007:20210723154237p:plain

やったこと

基本的な構成としてはAWS Lambda/Event Bridge/Ruby 2.7/LINE Messaging APIを使用して作りました。

 

肝としては10分に一回RSSを取得しに行くようにしたことと、その取得時間とRSSの作成時間を比較して直近のものだけをLINEに通知するようにしたところですね(防災情報などはできるだけ最新の情報がラグなくユーザーに届ける必要があるので)

 

今後

とりあえず、防災情報に関しては通知できるようになっているので実用性は高そう。

あとは実際に利用してくれるユーザーをいかに増やすかが課題になりそう

typeprofのインスタンス変数が未初期化のまま使われている警告を解消した

以下のPRをRubyに投げたところ、typeprof周りのテストで落ちているようだった。

github.com

で、どの辺が原因なのかtypeprofのテストを回してみたら以下の警告が表示されていた。

/home/sh/rubydev/typeprof/lib/typeprof/analyzer.rb:496: warning: instance variable @namespace not initialized

調べてみると、Ruby 3.0.0からは未初期化のインスタンス変数を使っていても警告が表示されなくなっており、今回テストで使用したRuby 2.7系列では警告が表示されているようだった。

bugs.ruby-lang.org

というわけで、Ruby 2.7系列でテストを実行した際に警告が表示されないようにPRを作った。

github.com

無事マージされたようなので何より。

浜田市の若者会議に選任された

この度、住んでいる浜田市の若者会議の委員に選任されました。

 

やることとしては、委員各々が持つスキルとかを使って若者が過ごしやすい街づくりを進める感じです

 

より詳しいことは下記のPDFを読んでいただければわかります。

https://www.city.hamada.shimane.jp/www/contents/1446178852885/files/senryakupu.pdf

 

今後に関しては僕の守備範囲であるIT系の話とかしつつ、住みやすい街づくりに協力できればと思います

雑にBacklogのチケットを一括で作成できるスクリプト書いた

はじめに

仕事の関係で一括でBacklogに複数のチケットを登録する必要があり、作成したものになります。 手作業なんて面倒くさいことしたくない人は是非使ってみてください。

作ったもの

github.com

使い方

使い方は簡単。 上記のコードをクローンした後、必要なAPIキーなどを.envに追加

SPACE_ID=<スペースID>
API_KEY=<APIキー>
PROJECT_ID=<プロジェクトID>
ISSUE_TYPE_ID=<チケットのタイプ>
PRIORITY_ID=<優先度>

その後、tickets.mdをクローンしたディレクトリ内に以下のように作成。

### ○○の修正対応

○○は××だったのでそのように修正

TICKET_END

### △△の修正対応

△△は××だったのでそのように修正

TICKET_END

TICKET_ENDで各チケット毎に区切るようにしています。

あとはbundle installなどをした後にbundle exec ruby main.rbを実行するだけです。

bundle exec ruby main.rb

参考

github.com

developer.nulab.com

高校生にプログラマーってどういう仕事か話してきた

経緯

Hamada.rbとかCoderDojo浜田とかでアレコレ作ったりしてたのがきっかけで知り合った方から「授業(という体のインタビュー)をしてみませんか?」とお誘い頂いたのがきっかけですね。

 

で、話を聞いてみると浜田高校では以下のような取り組みをしていて「地域の頑張っている人に話を聞く」ということをしているとのこと。

 

www.hamakou.ed.jp

 

面白い取り組みだったのと、こういう地方だとプログラマーに直接話を聞く機会とかもないだろうしと思ったので、快諾。

で、今日色々と仕事の話とかHamada.rbとかでやってるアプリ開発の話とか話してきました。

 

話した内容とか

Hamada.rbでやってるアプリ開発(避難先のGoogleMapアプリ)とかの話がメインで、それ以外に実際にプログラマーってどんな仕事かとかを話してきました。

アプリ開発の文脈で、ノーコードツールとかの話もしましたね。

 

意外と食いつきが良かったのは、実際に作ったアプリを見せた時ですね。

「どれぐらいでつくれるのか?」とか質問が来てました。

 

あと仕事の話も意外と興味をもって貰えたようでした。

浜田市とかだとプログラマーとして仕事している人はかなり少ないので、珍しかったのもありそう。

あと、リモートで働いているというのも面白かったみたいです。

 

今後とか

こういうのがきっかけでプログラミングに興味を持って貰える可能性はあるので、今後も参加できるようなら参加していきたいですねー。

 

あとは実際に高校生たちが考えたアプリとかを作ってみるのも面白いかもと思ったりしましたねー。