Web Components でどうなんだろう
最近、「Web制作者のためのCSS設計の教科書 を眺めました。Custom Elements の例を見ながら、以下のようなサンプルを書いてみました。
- コンポーネントの
class
を作成する。 attachShadow
で、シャドーDOMを使える?ようにする。customElement.define
でコンポーネントを登録する。名前には-
が入っている必要がある。- 既存の要素を拡張する場合は、
is
属性で登録したコンポーネントを使う。
あたりを押さえれば良いのかなぁと思いました。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>Card</h1> <card-element data-head="タイトル">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</card-element> <script type="application/javascript"> class Card extends HTMLDivElement { constructor() { super(); this.attachShadow({mode: 'open'}); const card = document.createElement('div'); card.setAttribute('class', 'card'); const cardHead = document.createElement('div'); cardHead.setAttribute('class', 'card-head'); cardHead.textContent = this.getAttribute('data-head') card.appendChild(cardHead); const cardBody = document.createElement('div'); cardBody.setAttribute('class', 'card-body'); card.appendChild(cardBody); cardBody.textContent = this.textContent; const style = document.createElement('style'); style.textContent = ` .card { background-color: #ffffff; border-radius: 0.4rem; border: 0.1rem solid #000000; box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.2) } .card-head { background-color: #f5f5f5; border-bottom: 0.1rem solid #c2c2c2; font-style: bolder; font-size: 1.2rem; letter-spacing: 0.1rem; padding: 0 0.4rem; text-align: center; } .card-body { padding: 1rem; } `; this.shadowRoot.appendChild(card); this.shadowRoot.appendChild(style); } } customElements.define('card-element', Card); </script> </body> </html>
React.js とかを使って、同じようにコンポーネントを作って、ページを構成していくけど、Safari がサポートしていれば、 autonomous components を使えば、Web Components の方が良い気がしている。
neovim で GitHub Copilot を試してみる
GitHub Copilot が、neovim でも使えるようになりましたね。プラグインの github/copilot.vim 、fugitive とか surround とかの素晴らしいプラグインの開発者である tpope さんです。
最初、Visual Studio Code で使えるようになって、次が neovim (と IntelliJ 系)なのは少し驚きです。
Getting started に記載されているように設定すれば、簡単に使うことができました。ただ、反応が少し遅くて、最初は、動作しているのかわかりませんでした。class User
と入力して、しばらくすれば以下のようなコードが保管されました…
class User < ActiveRecord::Base has_many :posts has_many :comments has_many :votes validates :username, presence: true, uniqueness: true validates :password, presence: true def password @password ||= BCrypt::Password.new(password_hash) end def password=(new_password) @password = BCrypt::Password.create(new_password) self.password_hash = @password end def self.authenticate(username, password) user = User.find_by_username(username) return user if user && user.password == password nil end end
class UsersController
だと scaffold したようなコードが補完されました。
しばらく、neovim で使っていこうと思います。
neovim で Language Server Protocol を利用してコード支援機能を実現してみる
この記事はMisoca+弥生 Advent Calendar 2019の2日目です。
先月末、 昨年に続いて、Safecast Hackathon に参加してきました。昨年のHackahtonぐらいから再開したポケモンGoはまだ細々と続けています。最近、毎週50kmの週間リワードも貰いますが、ボールが使い切れなくて困っています。
今回は、solargraph という ruby の Language Server を使って、neovim でコード補完や定義への移動をできるようにしてみましたので、その設定方法を紹介します。
Language Server Protocol (LSP) とは?
The Language Server protocol is used between a tool (the client) and a language smartness provider (the server) to integrate features like auto complete, go to definition, find all references and alike into the tool
Langserver.org でこのように定義されています。Language Server Protocol は、コード補完、定義への移動、参照箇所の検索というようなコード支援に必要な情報を提供する言語サーバーとその情報を受け取る開発ツール(クライアント)の間のやり取りを定めたものです。
Rubyの場合、vim-ruby (vim)、ruby-mode (emacs)、vscode-ruby (vscode) のように、コード支援機能は、開発ツールごとに実装されています。LSP を使うことで、言語サーバーがコード支援に必要な情報を提供して、開発ツールはクライアントとてして、その情報を受け取ることで、コード支援機能を提供することができるようになります。
Solargraph (言語サーバー) の設定
solargraph は、Ruby向けの言語サーバーです。コード補完やRubyの標準クラスの文書などの情報を提供します。
solargraph は rubygem として提供されているので、gem
コマンドで簡単にインストールできます。
$ gem install solargraph
デフォルトでは、ruby 2.2 向けの「core」(標準クラスのドキュメント)が同梱されています。list-cores
コマンドで確認できます。
$ solargraph list-cores 2.2.2
使用しているrubyのバージョンをcoreは、download-core
コマンドで取得します。available-cores
で取得可能なcoreを表示することができます。
$ solargraph available-cores 2.6.1 2.6.0 2.5.3 ... $ solargraph download-core 2.6.1
download-core
でバージョンを指定しない場合は、使用している(パスが通っている)rubyのバージョンにあうcoreを取得します。
プロジェクトで利用しているrubygemの文書を表示したい場合は、プロジェクトのルートディレクトリに移動して、bundle
コマンドを実行します。
$ solargraph bundle
Gemfile
を読み、必要な文書を取得します。
最後に config
コマンドで設定ファイルを作成します。プロジェクトのルートディレクトリに移動して実行します。
$ solargraph config
実行したディレクトリに.solargraph.yml
というファイルが作成されます。 Rails アプリケーションの場合、デフォルトの設定で問題ないと思います。興味がある方は、こちら を参照して下さい。
vim-lsp (クライアント)の設定
今回は、neovim で LSP クライアントとして、vim-lsp を使用します。async.vim も必要です。それぞれのプラグイン管理方法に応じた方法で2つのプラグインを追加します。
vim-lsp の Wikiページ にあるように ~/.config/nvim/init.vim
に以下を追加します。
if executable('solargraph') " gem install solargraph au User lsp_setup call lsp#register_server({ \ 'name': 'solargraph', \ 'cmd': {server_info->[&shell, &shellcmdflag, 'solargraph stdio']}, \ 'initialization_options': {"diagnostics": "true"}, \ 'whitelist': ['ruby'], \ }) endif
'initialization_options': {"diagnostics": "true"},
は、デバッグ用のログを出力するためなので、vim-lsp を正しく動作するように設定できたら、削除して良いと思います。。
次にコード補完のための設定をします。今回は、asyncomplete.vim を使います。このプラグインと asyncomplete-lsp.vim を追加します。そして、
inoremap <silent><expr> <TAB> \ pumvisible() ? "\<C-n>" : \ <SID>check_back_space() ? "\<TAB>" : \ asyncomplete#force_refresh() inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
という設定を ~/.config/nvim/init.vim
に追加すれば、コード補完ができるようになります。このように文字を入力すると候補が表示されます。Ctrl-N や Ctrl-P を使って、候補から選択します。
コマンドモードで:LspPeekDefinition
と入力すればカーソル上のクラスやメソッドの定義をポップアップに表示することができます。
LspDefinition
の場合は、定義されている場所に移動することができます。
その他の使用できるコマンドについては、ここ を参照して下さい。利用する言語サーバーによっては対応していないコマンドがあるようです。solargraph の場合、LspDeclaration
や LspPeekDecalation
は対応していないようでした。
まとめ
solargraph と vim-lsp を使って、neovim で、LSP を利用しての ruby のコード補完や定義への移動ができるように設定をしてみました。vim でも バージョン8なら、同じように設定できるようです。
当初は、RubyMine で LSP を利用するように設定をしてみたかったのですが、試してみたところ、ruby に関しては、RubyMine のコード支援機能が協力強力で、変化がなかったため、neovim で設定をしました。
明日、Misoca+弥生 Advent Calendar 2019の3日目は、ryotaro_kawakami さんです。
AWS Lambda を Elixir で実行してみる
先日、AWS re:Invent 2018 で AWS Lambda にて Custom Runtime という機能が発表されました。興味があったので「New for AWS Lambda – Use Any Programming Language and Share Common Components | AWS News Blog」を読んでいると We are also working with our partners to provide more runtimes: Erlang (Alert Logic) Elixir (Alert Logic) という記述があり、Elixir好きとして試してみることにしました。
ビルド用コンテナイメージの作成
まずはじめに Elixir コードをコンパイルするための Docker コンテナイメージをビルドします。Elixir で書いたコードを AWS Lambda 上で実行するには、実行する同じ環境でコードをコンパイルする必要があるようです。以下のように GitHub から取得してビルドします。
$ git clone https://github.com/alertlogic/erllambda_docker.git $ docker build -t erllambda:20.3-elixir erllambda_docker/elixir
プロジェクトの作成
コンテナを作成している間に Elixir プロジェクトを作成します。作成には、ローカル環境で Elixir が必要になります。
$ mix new hello_lambda $ cd hello_lambda
lib/hello_lambda.ex
を以下のように変更します。
defmodule HelloLambda do def handle(_event, _context) do {:ok, "Hello from Elixir"} end end
ファンクション名はhandle
とする必要があります。
mix.exs
を編集してLambdaにアップロードするためのZIPファイルを作成するための依存性を追加します。
defp deps do [ {:erllambda, "~> 2.0"}, {:mix_erllambda, "~> 1.0"} ] end
アップロードパッケージの作成
作成したコンテナを利用して以下のようにアップロードパッケージを作成します。
$ docker run -it --rm -v `pwd`:/buildroot -w /buildroot -e MIX_ENV=prod erllambda:20.3-elixir mix do deps.get, deps.compile, release.init, erllambda.release
本来なら release.init
の後で rel/config.exs
を確認すると良いのですが、今回は必要ないので一気にパッケージを作成します。
ビルドが成功すると _build/prod/rel/hello_lambda/releases/0.1.0/
内に hello_lambda.zip
が作成されているはずです。
Lambda 関数の作成
AWS コンソールにログインして Lambda 関数を作成します。ランタイムに「関数コードまたはレイヤーでカスタムランタイムを使用」を選択します。ロールは関数が実行できれば良いです。
関数が作成できたら作成したZIPファイルをアップロードします。アップロードする際は、ハンドラを「Elixir.HelloLambda」と指定して下さい。"HelloLambda"はプロジェクトでhandle
関数があるモジュール名です。
関数の実行
テストイベントを作成して関数を実行します。テストイベントは「Hello World」というテンプレートを利用して下さい。実行が成功するとこのようにログに表示されます。 デフォルトの設定のメモリが128MBでタイムアウトが3秒する場合があるので、失敗する場合はログを見ながら適宜変更してみて下さい。
感想
AWS Lambda の関数をElixir などの色々な言語で書くことができるようになり選択が広がるのは良いことだと思いました。JavaScript や Python での場合と比べると起動が遅いような気がします。何か Elixir だと良い Lambda 関数とかがあるのだろうか…
Safecast Hackathon 2018 に参加してきました
Safecast とは
Safecast に参加したきっかけ
Hackathon
最後に
Ruby東海 第48回勉強会
10月30日にRuby東海の第48回勉強会をエイチーム様の会議スペース(ルーセントタワー32階)をお借りして開催しました。参加者は8名で、初めての方がいなかったので、まったりとした勉強会でした。
- Vagrantを勉強しようとしている方がいたので、Ottoを勧めてみました。僕自身、Ottoが発表されたときに記事を斜め読みしたぐらいの知識しか無かったのですが、今から勉強するならと思って勧めてみました。近いうちに動かしてみてもう少し理解を深めようと思います。
- Jupyter(旧、iPython)の多言語対応って、すごいねという話しを少ししました。現在、Rubyを含めて、50言語ほど対応しているようです。Railsコンソールとして使うことができると面白そう。
- Coderetrietを名古屋でやろう!という話に何故かなりました。3年半ほど前に開催されて以来、開催されていないようです。是非、参加したいです。
相変わらず、Rubyについて、ほとんど話すことのない本編でした。懇親会は、いつものルーセントタワー地下1階にある名古屋丸八食堂でした。
- NetflixやHuluなどの動画サービスについての話をしました。僕は、最近、Huluで毎晩、ガンダム00を1話ずつ観ています。特にガンダムが好きとかいうわけではないですが、とりあえず、観ています。Netflixでは暖炉の動画が大人気らしいです。「ぱちぱち」と燃える音を聞きながら観ていると何となく心が和みます。YouTubeにも暖炉の動画が結構あがっているようです。
- 技術的負債を返済していきたいなぁという話をしました。返済していかないとモチベーションが下がっていくのでやりたい。だけど、理解を得ることができないので、返済する作業ができないという悪い循環にはまってしまっているようです。どこかで悪い循環を断ち切るきっかけを探すことができるといいですが、結論は出ませんでした。
懇親会でもRubyについてほとんど話していないので、もう少しRuby関連の話をしないとなぁと反省しています。
次回、第49回勉強会は、11月27日に開催する予定です。決定しましたら、Doorkeeper経由にて告知します。よろしくお願いします。