Home > database >  No require 'date' statement on my ruby file but I can call DateTime.now
No require 'date' statement on my ruby file but I can call DateTime.now

Time:01-15

I am trying to understand how importing files in ruby works. But I almost spent a whole day figuring out why I can call DateTime.now in my class where I didn't require 'date, these are all running on docker container instance where I get ruby 3.0.3 What got me stuck is when I tried to make a new ruby file on a new docker container instance ruby 3.0.3. And try calling DateTime.now it doesn't work.

I tried looking for require statement that has the word date in it in the project where I can call DateTime.now but no luck finding.

gem file of the project where I can call DateTime without require statement

gem 'aws-sdk-s3', '~> 1.93'
gem 'mime-types'
gem 'optparse', '~> 0.1.0'

group :development do
  gem 'rubocop', '~> 1.12'
end

group :test do
  gem 'rspec', '~> 3.10'
  gem 'rubocop-rspec', '~> 2.2'
  gem 'webmock', '~> 3.12'
end

gem file of the new project where I couldn't call DateTime without require statement

gem 'mime-types'
gem 'optparse', '~> 0.1.0'
gem 'gqli'

group :development do
  gem 'rubocop', '~> 1.12'
end

group :test do
  gem 'rspec', '~> 3.10'
  gem 'rubocop-rspec', '~> 2.2'
  gem 'webmock', '~> 3.12'
  gem 'test-unit', '~> 3.0'
end

the only difference is the aws and gqli in both project but I tried having both of them have the same gem file it still doesn't work.

CodePudding user response:

When you require the aws-sdk-s3 library, which is part of the aws-sdk-s3 Gem, the library, in turn, requires the aws-sdk-core library:

# frozen_string_literal: true

# WARNING ABOUT GENERATED CODE
#
# This file is generated. See the contributing guide for more information:
# https://github.com/aws/aws-sdk-ruby/blob/version-3/CONTRIBUTING.md
#
# WARNING ABOUT GENERATED CODE


require 'aws-sdk-kms'
require 'aws-sigv4'
require 'aws-sdk-core'
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

The aws-sdk-core library, which is part of the aws-sdk-core Gem, in turn, loads the param_converter library using Kernel#require_relative, as you can see here:

# client modules

require_relative 'aws-sdk-core/client_stubs'
require_relative 'aws-sdk-core/async_client_stubs'
require_relative 'aws-sdk-core/eager_loader'
require_relative 'aws-sdk-core/errors'
require_relative 'aws-sdk-core/pageable_response'
require_relative 'aws-sdk-core/pager'
require_relative 'aws-sdk-core/param_converter'
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

The param_converter library then, in turn, loads the date library:

# frozen_string_literal: true

require 'stringio'
require 'date'
#↑↑↑↑↑↑↑↑↑↑↑↑↑

The aws-sdk-core Gem does not depend on the date Gem:

> spec.add_dependency('jmespath', '~> 1', '>= 1.6.1') # necessary for secure jmespath JSON parsing
> spec.add_dependency('aws-partitions', '~> 1', '>= 1.651.0') # necessary for new endpoint resolution
> spec.add_dependency('aws-sigv4', '~> 1.5') # necessary for making Aws::STS, SSO, SSOOIDC API calls
> spec.add_dependency('aws-eventstream', '~> 1', '>= 1.0.2') # necessary for binary eventstream

But you don't have to depend on the date Gem in order to use the date library, because the date Gem is a default Gem, which means it is part of Ruby's standard library, gets maintained by the Ruby developers, doesn't need to be installed, doesn't need to be listed as a Gem dependency, and doesn't need to be activated.

So, that's why you don't have to require the date library yourself: because you require a library, which in turn requires another library, which in turn require_relatives another library, which in turn requires the date library.

But the more interesting question is, should you require the date library? And the answer is, Yes, you should. Relying on a require chain like this is extremely brittle: what if some library somewhere in the middle down this chain decides to change its internal structure and, e.g. validate dates using a different library or implement date validation themselves? Then your code breaks for no apparent reason.

The rule that I generally follow is that every script must stand on its own, i.e. every script must require all of its dependencies.

Now, in larger applications, this might get annoying, and might even lead to high startup latencies. A good example would be framework or a DSL, where it is simply expected that the framework or the DSL provides a set of libraries for you that are already pre-loaded. Imagine, you had to require every active_support library, active_model library, active_relation library, etc. you are using in a Ruby on Rails application. That would be stupid: if you write a Ruby on Rails model, you know that active_model is loaded, you don't need to load it again.

So, a slightly relaxed rule is: every script that is intended to be required or executed by a client must stand on its own. Scripts that are internal to the application may rely on internal knowledge about which libraries are already required.

  • Related