RubyのGemを自作してみた話。

###経緯

私は転職活動中の未経験エンジニアです。ふとRubyの基礎について理解が甘い、自信を持ってアピールできるアウトプットが欲しいと思いまして、Gemを自作する運びとなった訳であります。非常に単純ですが、hello Rubyと表示するGemを作っていきます。

###参考

こちらのドキュメントを参考にしました。
https://bundler.io/v2.0/guides/creating_gem.html


###準備

まずはbundlerをupdateします。最新のbundlerを使っていないことで発生する不具合を防ぎます。

```
$ gem update bundler
```

下記のメッセージが表示されたら成功しています。

```
Updating installed gems
Updating bundler
Fetching bundler-2.2.30.gem
Successfully installed bundler-2.2.30
Parsing documentation for bundler-2.2.30
Installing ri documentation for bundler-2.2.30
Installing darkfish documentation for bundler-2.2.30
Done installing documentation for bundler after 9 seconds
Parsing documentation for bundler-2.2.30
Done installing documentation for bundler after 2 seconds
Gems updated: bundler
kentaroyoshizumi@mbp RubyProject % bundler -v
Bundler version 2.2.30
```
gemのネーミングに関して、まずは名前に被りがないかを調べます。

```
$ gem search ^hello
```

下記のように表示されます。

```
*** REMOTE GEMS ***

Hello (0.0.0)
hello (0.0.1)
hello-aaron (1.0.0)
hello-asso-api (0.0.2)
hello-authentication (0.0.0)
hello-authorization (0.0.0)
hello-douglas (0.1.0)
hello-ebola (0.1.2)
hello-gem (0.1.0)
hello-hola (0.1.1)
hello-i18n (0.0.0)
hello-internationalization (0.0.0)
hello-isa (1.0.0)
hello-jesse (1.1.0)
hello-john (1.0.0)
hello-line (0.0.1)
hello-loser (1.0.0)
hello-magica (0.0.0)
hello-mama (1.0.0)
hello-management (0.0.0)
hello-matt (1.0.1)
hello-nabil (1.0.0)
hello-neversmile (0.1.1)
hello-parmeet (1.0.0)
hello-powergate (0.1.0)
hello-rails (0.5.1)
hello-registration (0.0.0)
hello-repsy (0.333)
hello-ruby-gem (0.0.0)
hello-ruby-station (0.3.0)
hello-rubygems (0.1.0)
hello-sense (0.1.0)
hello-tj (0.1.0)
hello-uptest (0.0.0)
hello-world (1.2.0)
hello-world-budmc29 (1.0)
hello-world-gem (0.1.0)
hello-world-rails (0.0.0)
hello-world-rubygems (0.1.1)
hello-world-test-an (0.1.0)
Hello-yali (0.0.1)
hello-zjy (1.0.7)
hello.ruby.gem (0.0.1)
hello1 (0.0.1)
Hello__World (0.0.1)
hello_actionrocket (0.0.0)
hello_ads (0.1.1)
hello_all (0.1.0)
hello_andiputra (0.0.0)
hello_andrew (0.0.0)
hello_anprichter (0.0.4)
hello_antonioricardo (0.1.1)
hello_anu (0.0.0)
hello_app (0.0.1)
hello_arun_first_gem (0.0.2)
hello_awa (0.0.0)
hello_bar (0.0.1)
hello_bilal (0.0.0)
hello_blip (0.0.4)
hello_boulder_rb (0.0.2)
hello_bundle_gem (0.1.1)
hello_code_active_record_utils (0.2.2)
hello_colo (0.0.2)
hello_command_line (0.1.0)
hello_cre8cre8 (0.1.0)
hello_cruel (0.0.0)
hello_crush (0.1.1)
hello_devJoao (0.1.0)
hello_dmdanilchenko (0.1.0)
hello_dolly (0.1.0)
hello_ejkiv (0.0.0)
hello_ext (0.0.1)
hello_falcon (0.1.0)
hello_fax (0.0.2)
hello_fjzink (0.0.1)
hello_friend (0.0.0)
hello_from_khalid (0.0.0)
hello_gem (0.0.1)
hello_gem_ddchen (0.0.1)
hello_gem_homeway (0.0.1)
hello_gem_rm (0.1.0)
hello_gem_test (0.0.0)
hello_goodbye (0.1.2)
hello_gy (0.0.1)
hello_hayashi (0.1.3)
hello_hiromi (0.1.0)
hello_hoge (0.1.0)
hello_hungnh (0.0.1)
hello_kalil (0.1.0)
hello_kao (0.2.0)
hello_karlingen (1.0.0)
hello_kelvinst (0.0.1)
〜〜〜〜〜〜中略〜〜〜〜〜〜〜〜
```

やばすぎでしょ。笑
Gemを自作してみようと試みた方が如何に多いか物語っています。
テストツールに何を使うか、CIをどうするかみたいなことが聞かれます。

```
$ bundle gem hello_ruby -t
Creating gem 'hello_ruby'...
Do you want to generate tests with your gem?
Future `bundle gem` calls will use your choice. This setting can be changed anytime with `bundle config gem.test`.
Enter a test framework. rspec/minitest/test-unit/(none): rspec
Do you want to set up continuous integration for your gem? Supported services:
* CircleCI:       https://circleci.com/
* GitHub Actions: https://github.com/features/actions
* GitLab CI:      https://docs.gitlab.com/ee/ci/
* Travis CI:      https://travis-ci.org/

Future `bundle gem` calls will use your choice. This setting can be changed anytime with `bundle config gem.ci`.
Enter a CI service. github/travis/gitlab/circle/(none): github
Do you want to license your code permissively under the MIT license?
This means that any other developer or company will be legally allowed to use your code for free as long as they admit you created it. You can read more about the MIT license at https://choosealicense.com/licenses/mit. y/(n): y
MIT License enabled in config
Do you want to include a code of conduct in gems you generate?
Codes of conduct can increase contributions to your project by contributors who prefer collaborative, safe spaces. You can read more about the code of conduct at contributor-covenant.org. Having a code of conduct means agreeing to the responsibility of enforcing it, so be sure that you are prepared to do that. Be sure that your email address is specified as a contact in the generated code of conduct so that people know who to contact in case of a violation. For suggestions about how to enforce codes of conduct, see https://bit.ly/coc-enforcement. y/(n): y
Code of conduct enabled in config
Do you want to include a changelog?
A changelog is a file which contains a curated, chronologically ordered list of notable changes for each version of a project. To make it easier for users and contributors to see precisely what notable changes have been made between each release (or version) of the project. Whether consumers or developers, the end users of software are human beings who care about what's in the software. When the software changes, people want to know why and how. see https://keepachangelog.com y/(n): y
Changelog enabled in config
Do you want to add rubocop as a dependency for gems you generate?
RuboCop is a static code analyzer that has out-of-the-box rules for many of the guidelines in the community style guide. For more information, see the RuboCop docs (https://docs.rubocop.org/en/stable/) and the Ruby Style Guides (https://github.com/rubocop-hq/ruby-style-guide). y/(n): y
RuboCop enabled in config
Initializing git repo in /Users/kentaroyoshizumi/Downloads/RubyProject/hello_ruby
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: 	git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: 	git branch -m <name>
      create  hello_ruby/Gemfile
      create  hello_ruby/lib/hello_ruby.rb
      create  hello_ruby/lib/hello_ruby/version.rb
      create  hello_ruby/hello_ruby.gemspec
      create  hello_ruby/Rakefile
      create  hello_ruby/README.md
      create  hello_ruby/bin/console
      create  hello_ruby/bin/setup
      create  hello_ruby/.gitignore
      create  hello_ruby/.rspec
      create  hello_ruby/spec/spec_helper.rb
      create  hello_ruby/spec/umbrella/report_spec.rb
      create  hello_ruby/.github/workflows/main.yml
      create  hello_ruby/LICENSE.txt
      create  hello_ruby/CODE_OF_CONDUCT.md
      create  hello_ruby/CHANGELOG.md
      create  hello_ruby/.rubocop.yml
Gem 'hello_ruby' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
```

作成したディレクトリに移動して、gitを入れていきます。

```
$ cd hello_ruby
($ git init
Reinitialized existing Git repository in home/RubyProject/hello_ruby/.git/  この部分は不要なようです。ご指摘ありがとうございます！)
$ git checkout -b main       //mainブランチに切り替える
$ git remote add origin https://github.com/KentaroYoshizumi/hello_ruby.git
//remoteリポジトリを登録
$ git push origin main   //GitHubにpush
Enumerating objects: 29, done.
Counting objects: 100% (29/29), done.
Delta compression using up to 4 threads
Compressing objects: 100% (24/24), done.
Writing objects: 100% (29/29), 8.15 KiB | 1.63 MiB/s, done.
Total 29 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/KentaroYoshizumi/hello_ruby.git
 + 15be057...a44ac57 main -> main (forced update)
```

次にgemspecを編集していきます。

```hello_ruby.gemspec
# frozen_string_literal: true

require_relative "lib/hello/ruby/version"

Gem::Specification.new do |spec|
  spec.name          = "hello_ruby"
  spec.version       = Hello::Ruby::VERSION
  spec.authors       = ["KentaroYoshizumi"]
  spec.email         = ["schecter3.2.1-@softbank.ne.jp"]

  spec.summary       = "test for making Ruby Gem."
  spec.description   = "test for making Ruby Gem."
  spec.homepage      = "https://github.com/KentaroYoshizumi."
  spec.license       = "MIT"
  spec.required_ruby_version = ">= 2.6.0"

  spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"

  spec.metadata["homepage_uri"] = "https://github.com/KentaroYoshizumi"
  spec.metadata["source_code_uri"] = "https://github.com/KentaroYoshizumi"
  spec.metadata["changelog_uri"] = "https://github.com/KentaroYoshizumi"

  # 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 do |f|
      (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
    end
  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

```

このようにファイルを編集した後、bundle installを実行します。

```
$ bundle install
Fetching gem metadata from https://rubygems.org/.........
Resolving dependencies...
Using rake 13.0.6
Following files may not be writable, so sudo is needed:
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/bin
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/build_info
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/build_info/mysql2-0.5.3.info
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/build_info/nokogiri-1.11.6-x86_64-darwin.info
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/build_info/nokogiri-1.11.7-x86_64-darwin.info
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/build_info/nokogiri-1.12.4-x86_64-darwin.info
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/cache
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/doc
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/extensions
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems
  /Users/kentaroyoshizumi/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/specifications
Using bundler 2.2.30
Fetching ast 2.4.2
Fetching diff-lcs 1.4.4
Fetching parallel 1.21.0
Fetching rainbow 3.0.0


Your user account isn't allowed to install to the system RubyGems.
  You can cancel this installation and run:

      bundle config set --local path 'vendor/bundle'
      bundle install

  to install the gems into ./vendor/bundle/, or you can enter your password
  and install the bundled gems to RubyGems using sudo.

  Password:


Your user account isn't allowed to install to the system RubyGems.
  You can cancel this installation and run:

      bundle config set --local path 'vendor/bundle'
      bundle install

  to install the gems into ./vendor/bundle/, or you can enter your password
  and install the bundled gems to RubyGems using sudo.

  Password:
Installing ast 2.4.2
Installing rainbow 3.0.0
Installing parallel 1.21.0
Installing diff-lcs 1.4.4
Using regexp_parser 2.1.1
Fetching rexml 3.2.5
Fetching rspec-support 3.10.2
Installing rexml 3.2.5
Fetching ruby-progressbar 1.11.0
Installing rspec-support 3.10.2
Installing ruby-progressbar 1.11.0
Fetching unicode-display_width 2.1.0
Installing unicode-display_width 2.1.0
Using umbrella-report 0.1.0 from source at `.`
Fetching parser 3.0.2.0
Fetching rspec-core 3.10.1
Fetching rspec-expectations 3.10.1
Installing parser 3.0.2.0
Fetching rspec-mocks 3.10.2
Installing rspec-expectations 3.10.1
Installing rspec-core 3.10.1
Installing rspec-mocks 3.10.2
Fetching rspec 3.10.0
Fetching rubocop-ast 1.12.0
Installing rspec 3.10.0
Installing rubocop-ast 1.12.0
Fetching rubocop 1.22.3
Installing rubocop 1.22.3
Bundle complete! 4 Gemfile dependencies, 19 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
```

このようにログが表示されたら、完了しています。

libディレクトリ下のhello_ruby.rbに処理を書いていきます。

```
# frozen_string_literal: true

require_relative "hello_ruby/version"

module HelloRuby
  class Error < StandardError; end
  # Your code goes here...
  puts "Hello, Ruby"    //新しく追加したコード
end

```

```
$ ./bin/console
Hello, Ruby
```

これで成功しています。全能感。