Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

自分用の gem template を作る #75

Closed
kachick opened this issue May 21, 2021 · 4 comments
Closed

自分用の gem template を作る #75

kachick opened this issue May 21, 2021 · 4 comments
Assignees
Labels

Comments

@kachick
Copy link
Owner

kachick commented May 21, 2021

Extracted from #72


とりあえず、今は?昔から? bundle gem とやらで template が作れるっぽいので、 最新の bundler(Bundler version 2.2.17) で試してみる。

なんでも ハイハイ とりあえず押してみたら、これだけ生成された。テストフレームワークは test-unit を選んだ。 CI まで選べるのびっくりした。

Initializing git repo in /Users/kachick/repos/tmp_gem/tmp_gem
      create  tmp_gem/Gemfile
      create  tmp_gem/lib/tmp_gem.rb
      create  tmp_gem/lib/tmp_gem/version.rb
      create  tmp_gem/tmp_gem.gemspec
      create  tmp_gem/Rakefile
      create  tmp_gem/README.md
      create  tmp_gem/bin/console
      create  tmp_gem/bin/setup
      create  tmp_gem/.gitignore
      create  tmp_gem/test/test_helper.rb
      create  tmp_gem/test/tmp_gem_test.rb
      create  tmp_gem/.github/workflows/main.yml
      create  tmp_gem/LICENSE.txt
      create  tmp_gem/CODE_OF_CONDUCT.md
      create  tmp_gem/CHANGELOG.md
      create  tmp_gem/.rubocop.yml
Gem 'tmp_gem' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html

そして生成された .rubocop.yml を見てみたら

AllCops:
  TargetRubyVersion: 2.4

Style/StringLiterals:
  Enabled: true
  EnforcedStyle: double_quotes

Style/StringLiteralsInInterpolation:
  Enabled: true
  EnforcedStyle: double_quotes

Layout/LineLength:
  Max: 120

となっていて、「無いな」という気持ちになった。
え、なに、 double_quotes 推奨なの? ruby style guide とか rubocop 標準でも無い気がするんだけど、敢えて?わからん・・・
とりあえず Default disabled じゃなくて ダブルクォート強制してきて line length 制限がある時点で、自分だったら関わりたくなくなってしまう。まぁ 80 文字とかじゃなくて 120文字 だから、それほどおかしくもない・・・か?いやー、でもその辺は「適当にやるから lint とか要らんわ」と思ってしまうな。 JavaScript の prettier 程浸透してたらもはや何も考えない気がするけど

.gitignore は、とてもシンプル。 GitHub の .gitignore とかと比べて大分少ないが、 「gem」 なのに Gemfile.lock を ignore しないのはどういう理屈なんだ?

/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

CODE_OF_CONDUCT.md は一応生成してみたが、とりあえず当面使う気ない #61 ので、細かく見ない

生成された test-unit のテンプレートは、 VERSION を const_defined? で見ているのがちょっと気になった。これは、なにか深い意味が有るのか・・・? 文字列じゃなくて提供することもあるとか? 自分は https://github.com/kachick/ruby-ulid/blob/5f3bc32328811a13bf0ce81e05b5336d318063f0/test/core/test_ulid_class.rb#L22-L28 こんな感じの test をしているんだが。

class TmpGemTest < Test::Unit::TestCase
  test "VERSION" do
    assert do
      ::TmpGem.const_defined?(:VERSION)
    end
  end

  test "something useful" do
    assert_equal("expected", "actual")
  end
end

Rakefile は、まぁ特に新しい発見ないかな・・・と思ったら、1行目が気になった。 #!/usr/bin/env rake みたいな shebang が無いのである。
rubocoo-rake とやらで permisson 不足を怒られてなるほどハイハイと付けたりしてたのだが、たしかに というか、別に Rakefile を直接叩く事なんて無いか・・・ 自分の shebang は一体いつどこからどう来たのかしらないが、とりあえずこれは確かになくて良いのかなという気がした。

# frozen_string_literal: true

require "bundler/gem_tasks"
require "rake/testtask"

Rake::TestTask.new(:test) do |t|
  t.libs << "test"
  t.libs << "lib"
  t.test_files = FileList["test/**/*_test.rb"]
end

require "rubocop/rake_task"

RuboCop::RakeTask.new

task default: %i[test rubocop]

ライセンスに関しては、ファイル名に「.txt」がついてるのがちょっとした発見だった。
前から付けたほうが良いのでは?と思ってたが、大半のプロジェクトで拡張子付けてない気がするので自分も付けないようにしていた。
が、 https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/licensing-a-repository 見てみると「.txt」を第一に推奨している。「.md」は「無いな」と思っているけど、つけるか付けないかに関しては自分も「.txt」つけるようにしようかな

README.md には何も参考になるところなさそう。

Gemfile にバージョンまで書かれていて、 gemspec にはなにもない。 #72 に書いた。

gemspec と Gemfile のどっちに依存性を書くべきなのか?問題 https://qiita.com/hirura/items/fe331672c8d41a1357e1 rubygems/bundler#7222 add_development_dependency は確かに test だけ切り離すとか出来なくて、なんでも Gemfile に書けばそれで良いのでは?と思っていたので、なるほど?だったのだけど、そうすると単純に rubygems.org に develeopment dependency が表示されなくなるのが「寂しい」という思いが有る。自分はあなたのこの gem を便利に使わせてもらっていますよ〜ということを、折角なので表明したい気持ちというか・・・ でもそれに対応するのはどちらかというと rubygems.org 側の責務では?という気はする・・・ 折衷案として、 依存関係自体は Gemfile に細かく書いたまま、 versioning を gemspec に書くようにしてみたりはした kachick/ruby-ulid#147

これは、やっぱ Gemfile にまとめるのが良いんだろうなー。そうするかー。

# frozen_string_literal: true

source "https://rubygems.org"

# Specify your gem's dependencies in tmp_gem.gemspec
gemspec

gem "rake", "~> 13.0"

gem "test-unit", "~> 3.0"

gem "rubocop", "~> 1.7"

しかし、この定義はどうなんだ? rake, test-unit, rubocop とどれも runtime dependency じゃないと思うんだけど グルーピングせずに書いてるのはそういうもんなんだっけ・・・?

require_relative "tmp_gem/version"

module TmpGem
  class Error < StandardError; end
  # Your code goes here...
end

肝心の Ruby コードはこんな感じになってて、あ、やっぱ class Error < StandardError; end を作るのは相変わらず常識的な感じで良いのかな?とちょっと思った。
ただ頭で version を require していて、まぁ普通だと思うんだけど、これだと今の irb の show_source で version 定義しか出なくなっちゃうんだよな・・・まぁ、irb 側を直すべきで、コード側が気にする話じゃないというのはそれはそう。

name: Ruby

on: [push,pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: 3.0.1
        bundler-cache: true
    - name: Run the default task
      run: bundle exec rake

.github 配下には、こんな action 定義が一つだけ。 matrix とか最初から定義しておいたほうが親切では?と思ったがまぁいいか。とりあえずこれから学ぶことはなさそう。
dependabot 定義も追加しておいたほうが今どき親切ではとは思った。(ならPR出せという話ではあるが・・・)

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here

bin/setup はこうである。いろんなリポジトリでこれ見るんだけど、手作業で? bundle install させるのと比べてなにかメリットが有るのだろうか。 bundle install 以外になにか色々必要な時ように、ここへまとめておけと言うぐらいの話なのかなー

# frozen_string_literal: true

require_relative "lib/tmp_gem/version"

Gem::Specification.new do |spec|
  spec.name          = "tmp_gem"
  spec.version       = TmpGem::VERSION
  spec.authors       = ["Kenichi Kamiya"]
  spec.email         = ["[email protected]"]

  spec.summary       = "TODO: Write a short summary, because RubyGems requires one."
  spec.description   = "TODO: Write a longer description or delete this line."
  spec.homepage      = "TODO: Put your gem's website or public repo URL here."
  spec.license       = "MIT"
  spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")

  spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"

  spec.metadata["homepage_uri"] = spec.homepage
  spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
  spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."

  # Specify which files should be added to the gem when it is released.
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
    `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
  end
  spec.bindir        = "exe"
  spec.executables   = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib"]

  # Uncomment to register a new dependency of your gem
  # spec.add_dependency "example-gem", "~> 1.0"

  # For more information and examples about making a new gem, checkout our
  # guide at: https://bundler.io/guides/creating_gem.html
end

さて、肝心の gemspec だが・・・あまり特別な感じはない。 description には summary より長い事書くはずだと思うんだけど、 rubygems.org はあんまそれを想定してない気がしてもにょる。
required_ruby_version の指定に文字列じゃなくて Gem::Requirement を使ってるのかー。ふーむ・・・Ruby のバージョニングが辞書順比較出来なくなる日は来ないと認識してるんだけど、一応か?
metadata は最近知ったけど、 allowed_push_host は知らんかったな。https://qiita.com/tossh/items/08e7165e730dbc1a0e2e ははぁ、会社内 gem とかでは使うと堅いみたいな感じかな。
files の指定に git ls-files 使ってて、おいおい結局この辺のベストプラクティスはなんなんだ?と思った。
#73, kachick/ruby-ulid#154 この辺で詰まって https://www.codinginthecrease.com/news_article/show/350843-using-git-in-your-gemspec こことか見て、確かに rails とかもそうしてるみただしな・・・と、基本的に Dir の glob とか使ってロードするようにしたんだけど、どうも気持ち悪い。やっぱ git 管理分だけがパッケージングされるよという安心感は強いと思っているので、個人的には dependabot が死なないよう回避しつつ git ls-files でフィルタリングをするような感じにするのが現状ベストかなと思っている。 https://github.com/kachick/ruby-ulid/blob/73df9f784e5d6444a6daccef314683ee62390435/ruby-ulid.gemspec#L49-L54 を更に書き換える感じで。

で、 bindir ってのは知らなかったな。こいつがなくても PATH に executable 入っちゃうと思うんだが、入れるとなにかメリットが有るのだろうか?
そしてまぁ、その bindir も executables も exe 前提である。#80 みたいな話はどこから来たのか・・・

https://docs.ruby-lang.org/ja/latest/class/Gem=3a=3aSpecification.html ちょっとここ見てみたら大量のオプションがあった。多分過去の遺物みたいなのもいっぱいあるんだろうけど、目を通したほうが良いのだろうか・・・ => 見たよ。でもそんなに有益そうなのは無かった。

test_files が無いのは https://pocke.hatenablog.com/entry/2020/10/24/171955 見て知ってた。 rubygems/guides#90 でguideから消えたみたいだけど、後方互換性のためとはいえなんの warning も出さずに値を設定できてしまうフィールドがずっと残るのはどうなんだろうなぁ・・・
rubygems/bundler#3207 👀

さて、前回はtest-unitだったわけだけど、rspecも適当に使いたい時があるのでrspec選んで作ってみようと思ってもっかい bundle gem another_gem_name を叩いたら、インタラクティブなのが何もなく、前回と同じ設定で作られてしまった。
bundle config を叩くとわかるが、一度選んだものはグローバルに設定が保存されるらしい・・・これさぁ・・・要るかぁ?gemなんて毎回結構要件とか変わるもんじゃない?しかも bundle config unset がパターンを受け取ってくれないっぽくて、手動で全部消す羽目になった・・・だ、だめだ。 bundler に対して苦手意識ばかり募ってゆく・・・

まぁ、どうせ template 自作して bundle gem を頻繁に叩くことはなくなるようにしようとしてるわけだから深く考えないことにする。
今度は rspec 以外殆どパスしてこんな感じだ

Initializing git repo in /Users/kachick/repos/tmp_gem_rspe
      create  tmp_gem_rspec/Gemfile
      create  tmp_gem_rspec/lib/tmp_gem_rspec.rb
      create  tmp_gem_rspec/lib/tmp_gem_rspec/version.rb
      create  tmp_gem_rspec/tmp_gem_rspec.gemspec
      create  tmp_gem_rspec/Rakefile
      create  tmp_gem_rspec/README.md
      create  tmp_gem_rspec/bin/console
      create  tmp_gem_rspec/bin/setup
      create  tmp_gem_rspec/.gitignore
      create  tmp_gem_rspec/.rspec
      create  tmp_gem_rspec/spec/spec_helper.rb
      create  tmp_gem_rspec/spec/tmp_gem_rspec_spec.rb
      create  tmp_gem_rspec/.github/workflows/main.yml
      create  tmp_gem_rspec/LICENSE.txt

全部の差分を見るつもりはないが、rspecに関わりそうなところを見に行く。

Rakefile

# frozen_string_literal: true

require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task default: :spec

Gemfile

# frozen_string_literal: true

source "https://rubygems.org"

# Specify your gem's dependencies in tmp_gem_rspec.gemspec
gemspec

gem "rake", "~> 13.0"

gem "rspec", "~> 3.0"

.rspec

--format documentation
--color
--require spec_helper

ここまでは、まぁそんなもんか?と思った。 rspec の --color は適当だった気がするので、これは貰っておくか。
--format documentation を自分が積極的に使うことはない気がする。

.gitignore

/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

# rspec failure tracking
.rspec_status

え、.rspec_status なんて生成されることがあんの・・・?見たこと無いし、ぐぐってもあんま情報無いんだけど・・・

https://github.com/search?q=org%3Arspec+.rspec_status&type=code

screen_shot 2021-05-29 22 50 39

よくわからんけど、 outdatd な気がするな・・・

spec_helper.rb

# frozen_string_literal: true

require "tmp_gem_rspec"

RSpec.configure do |config|
  # Enable flags like --only-failures and --next-failure
  config.example_status_persistence_file_path = ".rspec_status"

  # Disable RSpec exposing methods globally on `Module` and `main`
  config.disable_monkey_patching!

  config.expect_with :rspec do |c|
    c.syntax = :expect
  end
end

disable_monkey_patching! は自分も付けるようにしてる。
そしてここで .rspec_status が出てきた。ファイル名自体は何でもよくて、 example_status_persistence_file_path の方が大事なのかな。
https://github.com/rspec/rspec-core/blob/ea8554afd1a2b63677c6593059fa8f2476181deb/spec/rspec/core/world_spec.rb#L233-L248 全くわからん。

https://qiita.com/igrep/items/cd1d2ba8ce5ccb6f5f44#33%E3%81%A7%E3%81%AE%E5%A4%89%E6%9B%B4-core-new---only-failures-option

そして--only-failuresオプションを使用すると、名前通りこのファイルを見て、「最後にrspecを実行した時に失敗したexampleのみ実行」してくれるようになりました。素晴らしい! 😄

おーなるほど?んー、大規模プロジェクトでは確かに便利な感じがあるな・・・覚えてはおこう。

syntax = :expect は、多分そんな感じだろうと思ったけど、やっぱ expect に限定する感じか。 https://relishapp.com/rspec/rspec-expectations/docs/syntax-configuration
disable_monkey_patching! がカバーするのでは?と思ったけど、 should の記法増えたみたいな話聞いた気もするしそれを防ぐ感じなのかな?まぁ、自分も ruby/spec 以外で should 使った記憶がないので入れておくか。

# frozen_string_literal: true

RSpec.describe TmpGemRspec do
  it "has a version number" do
    expect(TmpGemRspec::VERSION).not_to be nil
  end

  it "does something useful" do
    expect(false).to eq(true)
  end
end

VERSION の確認の仕方が、test-unitのときより雑である。もうこれは、適当にやってくれということなのだと理解した。

というところで、大体今の bundle gem からは学んだ気がする。正直言ってあんまメンテされてない感を受けるんだが・・・まぁいいか、知らないや。

@kachick kachick added the ruby label May 21, 2021
@kachick kachick self-assigned this May 21, 2021
kachick added a commit to kachick/irb-power_assert that referenced this issue May 24, 2021
kachick added a commit to kachick/irb-power_assert that referenced this issue May 24, 2021
kachick added a commit to kachick/ruby-ulid that referenced this issue May 24, 2021
kachick added a commit to kachick/ruby-ulid that referenced this issue May 24, 2021
kachick added a commit to kachick/rspec-matchers-power_assert_matchers that referenced this issue May 24, 2021
kachick added a commit to kachick/ruby-ulid that referenced this issue May 24, 2021
@kachick
Copy link
Owner Author

kachick commented May 29, 2021

test-unit と rspec 混合の形で作った https://github.com/kachick/ruby-gem-template 以降はこいつを適宜 update する感じでやっていく。
疲れた・・・

@kachick
Copy link
Owner Author

kachick commented Jan 24, 2023

gemspec と Gemfile のどっちに依存性を書くべきなのか?問題 https://qiita.com/hirura/items/fe331672c8d41a1357e1
これは、やっぱ Gemfile にまとめるのが良いんだろうなー。そうするかー。

ついこないだ rubocop に入ったみたいだけど、rubocop/rubocop#11469 で現在進行系で議論されてるので、デフォルトに残り続けるかはどうなんだろうか。

本家の discussion は止まっているし rubygems/rubygems#5065

@koic
Copy link

koic commented Jan 24, 2023

何らかの結論があるわけではないのですが、かつて Asakusa.rb で情報収集した以下の議論メモは何らかの参考にする可能性があります。
https://koic.hatenablog.com/entry/gemspec-vs-gemfile-for-development-dependency-gems

まだデフォルト問題に対して個人の好みを超えた解決案を持っていないため、見守っているところでした。

@kachick
Copy link
Owner Author

kachick commented Jan 24, 2023

おぉ、この件で調べてたときに確かあたったと思われるブログの著者から直接返信が 🙏 ありがとうございます。

個人的に add_development_dependency を使うメリットは rubygems.org で他の gem へのリンクが貼られるぐらいしか感じていなかったんですが、なるほど複数 Gemfile 時の共通化部分として利用ですか。

自分が複数 Gemfile 持つ時は Gemfile 内で依存gemのバージョンを分ける事が多かったので、その用途が使用できるシーンは無かったのかな・・・? 一時 add_development_dependency にバージョン抜きで記述して、 Gemfile 側に詳細なバージョン入れたりもしてたんですが、あまり意味ないですもんね・・・

kachick added a commit to kachick/declare that referenced this issue Jan 26, 2023
* Update rubocop requirement from ~> 1.43.0 to ~> 1.44.1

Updates the requirements on [rubocop](https://github.com/rubocop/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop/rubocop/releases)
- [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md)
- [Commits](rubocop/rubocop@v1.43.0...v1.44.1)

---
updated-dependencies:
- dependency-name: rubocop
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>

* Update gemspec in examples

See below issues

rubocop/rubocop#11469
https://github.com/rubygems/rubygems/discussions/5065
kachick/times_kachick#75 (comment)
https://koic.hatenablog.com/entry/gemspec-vs-gemfile-for-development-dependency-gems

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kenichi Kamiya <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants