stibium-bundled 0.0.1 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 872a10da7e3924dd1b8dca69f57bcbd7f31ab6b82097b3cd45ddfaf4ff8e0aa9
4
- data.tar.gz: 97e4ccd6cd8211e1e4ad9d8ab63feec5294168b8971187ad44d6d80ee78c957b
3
+ metadata.gz: 3be68fcb9db04232974861f121d822dec6236d7b45a6ed3eec003d1814811e77
4
+ data.tar.gz: 3962f200a155fe9931eafc6664c3fb1787d6c25378fcd54c45b38b013bf7da5d
5
5
  SHA512:
6
- metadata.gz: 1c253d6972da289b0ef2c78826e3d4b88d17fd19370afe47938c1cc44d6c79fd47a22f05312ade86318059e6d97c8a85937c9ed2b7817d4156ca63a4ff757479
7
- data.tar.gz: 38c53b363286e39f45360d12717e9c5dd262906b770b04759e8ab7231b283175484fe674ae8d89db3a31b4cb83fe41c07bb179a5d507871312e2ebed4e5e5e8d
6
+ metadata.gz: dc8e6621dabc968957985f69253abae2f02c5909f51c906b8298b1cd4e9ef19ad038a9bab0aa743272f06e59d3baed1bf7155c83ee888762e5ef10e0a5d1a1c4
7
+ data.tar.gz: '08eb70137990b8174da7d5165c965d45b4c9820d0469ed5601aafecffd1378615aff8f97398e1ac6db75cce28c290cf5d98fa1c6711332ccb75dc715c3d5a7d2'
data/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # ``stibium-bundled`` [![Gem Version](https://badge.fury.io/rb/stibium-bundled.svg)][rubygems:stibium-bundled] [![Maintainability](https://api.codeclimate.com/v1/badges/7121242b44c7a3cc4f61/maintainability)](https://codeclimate.com/github/SwagDevOps/stibium-bundled/maintainability)
2
+
3
+ This gem is intended to mimic Bundler's behavior and conform to [bundler configuration options][bundler:config].
4
+
5
+ ``stibium-bundled`` detects ``gems.rb`` and ``gems.locked``
6
+ (or ``Gemfile`` and ``Gemfile.lock``)
7
+ and [``bundler/setup``][bundler:setup] (for [standalone][man:install#options] installation).
8
+
9
+ ``standalone`` makes a bundle that can work __without depending__ on Bundler (or Rubygems) at runtime. Bundler generates
10
+ a ``bundler/setup.rb`` file to replace Bundler's own setup in the manner required.
11
+
12
+ [Configuration settings][bundler:config] are loaded in this order:
13
+
14
+ 1. Local config (``.bundle/config`` or ``"$BUNDLE_APP_CONFIG/config``)
15
+ 2. Environment variables (``ENV``)
16
+ 3. Global config (``~/.bundle/config``)
17
+ 4. Default config
18
+
19
+ ## Sample of use
20
+
21
+ ```ruby
22
+ # file: lib/awesome_gem.rb
23
+
24
+ require 'stibium/bundled'
25
+
26
+ module AwesomeGem
27
+ include(Stibium::Bundled)
28
+
29
+ self.bundled_from("#{__dir__}/..", setup: true)
30
+ end
31
+ ```
32
+
33
+ or more concise:
34
+
35
+ ```ruby
36
+ # file: lib/awesome_gem.rb
37
+
38
+ require 'stibium/bundled'
39
+
40
+ module AwesomeGem
41
+ include(Stibium::Bundled).bundled_from("#{__dir__}/..", setup: true)
42
+ end
43
+ ```
44
+
45
+ or load a gem depending on status:
46
+
47
+ ```ruby
48
+ # file: lib/awesome_gem.rb
49
+
50
+ require 'stibium/bundled'
51
+
52
+ module AwesomeGem
53
+ include(Stibium::Bundled).bundled_from("#{__dir__}/..", setup: true) do |bundle|
54
+ if Object.const_defined?(:Gem) and bundle.locked? and bundle.installed?
55
+ 'foo-bar'.tap do |gem_name|
56
+ unless bundle.specifications.keep_if { |spec| spec.name == gem_name }.empty?
57
+ require gem_name.gsub('-', '/')
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ ```
64
+
65
+ if ``stibium-bundled`` is not system wide installed, it can be necessary to
66
+ locate it:
67
+
68
+ ```ruby
69
+ # file: lib/awesome_gem.rb
70
+
71
+ autoload(:Pathname, 'pathname')
72
+ autoload(:RbConfig, 'rbconfig')
73
+
74
+ module AwesomeGem
75
+ Pathname.new("#{__dir__}/..").expand_path.yield_self do |basedir|
76
+ begin
77
+ require 'stibium/bundled'
78
+ rescue LoadError
79
+ [
80
+ [RUBY_ENGINE, RbConfig::CONFIG.fetch('ruby_version'), 'bundler/gems/*/stibium-bundled.gemspec'],
81
+ [RUBY_ENGINE, RbConfig::CONFIG.fetch('ruby_version'), 'gems/stibium-bundled-*/lib/'],
82
+ ].map { |parts| basedir.join(*['{**/,}bundle'].concat(parts)) }.yield_self do |patterns|
83
+ Pathname.glob(patterns).first&.dirname.tap { |gem_dir| require gem_dir.join('lib/stibium/bundled') }
84
+ end
85
+ end
86
+
87
+ include(::Stibium::Bundled).bundled_from(basedir, setup: true) do |bundle|
88
+ if bundle.locked? and bundle.installed? and Object.const_defined?(:Gem)
89
+ require 'fabulous/feature' if bundle.specifications.keep_if { |s| s.name == 'fabulous' }.any?
90
+ end
91
+ end
92
+ end
93
+ end
94
+ ```
95
+
96
+ ## Benchmarks
97
+
98
+ Using ``Stibium::Bundled`` setup leads to minor overhead compared to direct require for ``bundler/setup``,
99
+ on the other hand ``Stibium::Bundled`` setup is compatible with standalone's bundler setup without code change.
100
+ And ``bundle exec`` is known to be [slow][stackoverflow/running-scripts-with-bundle-exec-is-slow].
101
+
102
+ Install [hypefine][sharkdp/hyperfine] and run benchmarks:
103
+
104
+ ```shell
105
+ rake bench runs=20
106
+ ```
107
+
108
+ | Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
109
+ |:---|---:|---:|---:|---:|
110
+ | `bundler/setup` | 205.7 ± 7.1 | 200.1 | 232.5 | 1.00 ± 0.05 |
111
+ | `bundled` | 205.7 ± 6.2 | 196.8 | 222.4 | 1.00 |
112
+ | `bundle exec` | 559.4 ± 13.0 | 543.2 | 587.8 | 2.72 ± 0.10 |
113
+
114
+ ## Install
115
+
116
+ ```sh
117
+ bundle config set --local clean 'true'
118
+ bundle config set --local path 'vendor/bundle'
119
+ bundle install --standalone
120
+ ```
121
+
122
+ <!-- hyperlinks -->
123
+
124
+ [rubygems:stibium-bundled]: https://rubygems.org/gems/stibium-bundled
125
+ [bundler:config]: https://bundler.io/v2.2/bundle_config.html
126
+ [bundler:setup]: https://bundler.io/v1.5/bundler_setup.html
127
+ [man:install#options]: https://bundler.io/man/bundle-install.1.html#OPTIONS
128
+ [sharkdp/hyperfine]: https://github.com/sharkdp/hyperfine
129
+ [stackoverflow/running-scripts-with-bundle-exec-is-slow]: https://stackoverflow.com/questions/13894966/running-scripts-with-bundle-exec-is-slow
@@ -17,72 +17,95 @@ end
17
17
  # ```ruby
18
18
  # # file: lib/awesome_gem.rb
19
19
  # module AwesomeGem
20
- # Stibium::Bundled.call(self, basedir: "#{__dir__}/..")
20
+ # include(Stibium::Bundled)
21
21
  #
22
- # bundled&.tap do |bundle|
23
- # unless bundle.standalone!
24
- # require 'bundler/setup' if bundle.locked?
25
- # end
26
- # end
22
+ # self.bundled_from("#{__dir__}/..", setup: true)
27
23
  # end
28
24
  # ```
29
- #
30
- # or:
31
- #
32
- # ```ruby
33
- # # file: lib/awesome_gem.rb
34
- # module AwesomeGem
35
- # class << self
36
- # include(Stibium::Bundled)
37
- # end
38
- #
39
- # self.bundled_from("#{__dir__}/..") do |bundle|
40
- # unless bundle.standalone!
41
- # require 'bundler/setup' if bundle.locked?
42
- # end
43
- # end
44
- # end
45
25
  module Stibium::Bundled
46
26
  {
47
27
  Bundle: 'bundle',
48
28
  VERSION: 'version',
49
29
  }.each { |k, v| autoload(k, "#{__dir__}/bundled/#{v}") }
50
30
 
51
- # @!method bundled?
52
- # Denote bundle is locked or standalone.
53
- # @return [Boolean]
31
+ class << self
32
+ private
54
33
 
55
- # @!method bundled
56
- # @return [Bundle, nil]
34
+ # Callback invoked whenever the receiver is included in another module or class.
35
+ #
36
+ # @param [Class, Module] othermod
37
+ #
38
+ # @see https://ruby-doc.org/core-2.5.3/Module.html#method-i-included
39
+ def included(othermod)
40
+ othermod.singleton_class.__send__(:include, self) unless othermod.singleton_class?
41
+ end
42
+ end
57
43
 
58
- # @param [String, Pathname] basedir
44
+ # Denote bundle is locked or standalone.
45
+ #
46
+ # @return [Boolean]
47
+ #
48
+ # @see .call
49
+ def bundled?
50
+ false
51
+ end
52
+
53
+ # @return [Bundle, nil]
54
+ #
55
+ # @see .call
56
+ def bundled
57
+ nil
58
+ end
59
+
60
+ protected
61
+
62
+ # @param basedir [String, Pathname]
63
+ # @param setup [Boolean, Array<Symbol>]
64
+ # @param env [Hash{String => String}]
65
+ # @param ruby_config [Hash{Symbol => Object}]
59
66
  #
60
67
  # @return [Bundle. nil]
61
- def bundled_from(basedir)
62
- Stibium::Bundled
63
- .call(self, basedir: basedir)
64
- .bundled
65
- .tap { |bundle| yield(bundle) if block_given? and bundle }
68
+ #
69
+ # @see Stibium::Bundled::Bundle#setup
70
+ def bundled_from(basedir, setup: false, env: ENV.to_h, ruby_config: {})
71
+ # @type [Stibium::Bundled::Bundle] bundle
72
+ Stibium::Bundled.call(self, basedir: basedir, env: env, ruby_config: ruby_config).bundled&.tap do |bundle|
73
+ bundle.__send__(:setup, **{ guards: setup.is_a?(Array) ? setup : nil }.compact) if setup
74
+
75
+ yield(bundle) if block_given?
76
+ end
66
77
  end
67
78
 
68
79
  class << self
69
80
  # @param target [Class, Module]
70
81
  # @param basedir [String, Pathname]
82
+ # @param env [Hash{String => String}]
83
+ # @param ruby_config [Hash{Symbol => Object}]
71
84
  #
72
- # @return [Class, Module]
73
- def call(target, basedir:)
85
+ # @return [Class, Module] given ``Class`` or ``Module``
86
+ def call(target, basedir:, env: ENV.to_h, ruby_config: nil)
74
87
  target.tap do |t|
75
88
  t.singleton_class.tap do |sc|
76
89
  sc.singleton_class.__send__(:include, self)
77
- sc.define_method(:bundled?) { !bundled?.nil? }
90
+ sc.define_method(:bundled?) { !bundled.nil? }
78
91
  sc.define_method(:bundled) do
79
- # @type [Bundle] bundle
80
- # rubocop:disable Style/TernaryParentheses
81
- Bundle.new(basedir).yield_self { |bundle| (bundle.locked? or bundle.standalone?) ? bundle : nil }
82
- # rubocop:enable Style/TernaryParentheses
92
+ Stibium::Bundled.__send__(:bundler).call(basedir, env: env, ruby_config: ruby_config)
83
93
  end
84
94
  end
85
95
  end
86
96
  end
97
+
98
+ protected
99
+
100
+ # @api private
101
+ #
102
+ # @return [Proc]
103
+ def bundler
104
+ lambda do |basedir, env:, ruby_config: nil|
105
+ Bundle.new(basedir, env: env, ruby_config: ruby_config).yield_self do |bundle|
106
+ bundle.bundled? ? bundle : nil
107
+ end
108
+ end
109
+ end
87
110
  end
88
111
  end
@@ -11,19 +11,36 @@ require_relative '../bundled'
11
11
  # Describe a bundle.
12
12
  class Stibium::Bundled::Bundle
13
13
  autoload(:Pathname, 'pathname')
14
+ autoload(:Gem, 'rubygems') # @see .specifications
15
+
16
+ {
17
+ Config: 'config',
18
+ Directory: 'directory',
19
+ }.each { |k, v| autoload(k, "#{__dir__}/bundle/#{v}") }
14
20
 
15
21
  # @return [Pathname]
16
22
  attr_reader :path
17
23
 
24
+ # @return [Config]
25
+ attr_reader :config
26
+
27
+ # @return [Directory]
28
+ attr_reader :directory
29
+
18
30
  # @param path [String, Pathname]
31
+ # @param env [Hash{String => String}]
32
+ # @param ruby_config [Hash{Symbol => Object}]
19
33
  #
20
34
  # @raise [Errno::ENOENT]
21
35
  # @raise [ArgumentError] when given ``path`` is not a directory.
22
- def initialize(path)
36
+ def initialize(path, env: ENV.to_h, ruby_config: {})
23
37
  self.tap do
24
- @path = Pathname.new(path).realpath.freeze
38
+ (@path = Pathname.new(path).realpath.freeze).tap do |base_path|
39
+ raise ArgumentError, 'path is not a directory' unless base_path.directory?
40
+ end
25
41
 
26
- raise ArgumentError, 'path is not a directory' unless self.path.directory?
42
+ @config = Config.new(self.path, env: env).freeze
43
+ @directory = Directory.new(self.bundle_path, ruby_config: ruby_config).freeze
27
44
  end.freeze
28
45
  end
29
46
 
@@ -38,7 +55,30 @@ class Stibium::Bundled::Bundle
38
55
  #
39
56
  # @return [Boolean]
40
57
  def locked?
41
- !!gemfiles[1]
58
+ !!gemfiles&.fetch(1, nil)
59
+ end
60
+
61
+ # Get specifications.
62
+ #
63
+ # @see https://docs.ruby-lang.org/en/3.0.0/Gem/Specification.html
64
+ #
65
+ # @return [Array<Gem::Specification>]
66
+ def specifications
67
+ directory.specifications.map { |file| instance_eval(file.read, file.to_path) }.sort_by(&:name)
68
+ end
69
+
70
+ # Denote install seems to be happened (since specifications are present).
71
+ #
72
+ # @return [Boolean]
73
+ def installed?
74
+ !directory.specifications.empty?
75
+ end
76
+
77
+ # Denote bundle seems installed by bundler.
78
+ #
79
+ # @return [Boolean]
80
+ def bundled?
81
+ locked? or standalone?
42
82
  end
43
83
 
44
84
  # Get path to gemfile.
@@ -47,7 +87,7 @@ class Stibium::Bundled::Bundle
47
87
  #
48
88
  # @return [Pathname, nil]
49
89
  def gemfile
50
- gemfiles[0]
90
+ gemfiles&.fetch(0, nil)
51
91
  end
52
92
 
53
93
  # Get gemfile files (gemfile + lockfile) or nothing.
@@ -67,23 +107,71 @@ class Stibium::Bundled::Bundle
67
107
  #
68
108
  # @return [Boolean]
69
109
  def standalone?
70
- standalone_setupfile.file?
110
+ bundler_setup.yield_self { |fp| fp.file? and fp.readable? }
71
111
  end
72
112
 
73
- # Load standalone setup if present
113
+ protected
114
+
115
+ # Load standalone setup if present.
74
116
  #
75
- # @return [Boolean]
76
- def standalone!
117
+ # @return [self]
118
+ #
119
+ # @raise [Errno::ENOENT, LoadError]
120
+ def standalone!(&fallback)
77
121
  # noinspection RubyResolve
78
- standalone?.tap { |b| require standalone_setupfile if b }
122
+ require(bundler_setup.realpath)
123
+ rescue Errno::ENOENT, LoadError => e
124
+ fallback ? fallback.call(self) : raise(e)
125
+ ensure
126
+ self
79
127
  end
80
128
 
81
- protected
129
+ # Load standalone setup if present, else fallback to <code>bundler/setup</code>.
130
+ #
131
+ # Load Bundler's setup (<code>bundler/setup</code>) when all guards are ``true``,
132
+ # as a result, default behavior, is to load <code>bundler/setup</code>
133
+ # only when locked and installed.
134
+ #
135
+ # @param guards [Array<Symbol>]
136
+ #
137
+ # @return [self]
138
+ #
139
+ # @raise [LoadError] when <code>bundle/setup</code> is loaded and bundler is not present.
140
+ #
141
+ # @see https://bundler.io/v1.5/bundler_setup.html
142
+ # @see https://github.com/ruby/ruby/blob/0e40cc9b194a5e46024d32b85a61e651372a65cb/lib/bundler.rb#L139
143
+ # @see https://github.com/ruby/ruby/blob/0e40cc9b194a5e46024d32b85a61e651372a65cb/lib/bundler/setup.rb
144
+ # @see https://github.com/ruby/ruby/blob/69ed64949b0c02d4b195809fa104ff23dd100093/lib/bundler.rb#L11
145
+ # @see https://github.com/ruby/ruby/blob/69ed64949b0c02d4b195809fa104ff23dd100093/lib/bundler/rubygems_integration.rb
146
+ def setup(guards: [:bundled, :installed])
147
+ self.tap do
148
+ unless guards.map { |s| self.public_send('%s?' % s.to_s.gsub(/\?$/, '')) }.include?(false)
149
+ standalone! { require 'bundler/setup' }
150
+ end
151
+ end
152
+ end
153
+
154
+ # @return [Pathname]
155
+ def bundle_path
156
+ Pathname.new(config.fetch('BUNDLE_PATH')).yield_self do |bundle_path|
157
+ (bundle_path.absolute? ? bundle_path : path.join(bundle_path))
158
+ end
159
+ end
82
160
 
161
+ # Standalone setup file.
162
+ #
163
+ # ``bundle install --standalone[=<list>]`` makes a bundle that can work without depending on
164
+ # Rubygems or Bundler at runtime.
165
+ # A space separated list of groups to install has to be specified.
166
+ # Bundler creates a directory named ``bundle`` and installs the bundle there.
167
+ # It also generates a ``bundle/bundler/setup.rb`` file to replace Bundler's own setup in the manner required.
168
+ #
83
169
  # @see #standalone?
170
+ # @see #standalone!
171
+ # @see https://bundler.io/v2.2/man/bundle-install.1.html#OPTIONS
84
172
  #
85
173
  # @return [Pathname]
86
- def standalone_setupfile
87
- path.join('bundle', 'bundler', 'setup.rb')
174
+ def bundler_setup
175
+ bundle_path.join('bundler/setup.rb')
88
176
  end
89
177
  end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2020-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../bundle'
10
+
11
+ # Describe bundler configuration settings.
12
+ #
13
+ # Bundler loads configuration settings in this order:
14
+ #
15
+ # 1. Local config (``.bundle/config`` or ``$BUNDLE_APP_CONFIG/config``)
16
+ # 2. Environment variables (``ENV``)
17
+ # 3. Global config (``~/.bundle/config``)
18
+ # 4. Bundler default config - PARTIAL support is implemented in ``Config.defaults``
19
+ #
20
+ # @note Executing bundle with the ``BUNDLE_IGNORE_CONFIG`` environment set will cause it to ignore all configuration.
21
+ #
22
+ # @see https://bundler.io/v2.2/bundle_config.html
23
+ # @see https://evilmartians.com/chronicles/ruby-on-whales-docker-for-ruby-rails-development
24
+ # @see .load
25
+ # @see .read
26
+ # @see .env
27
+ # @see .defaults
28
+ class Stibium::Bundled::Bundle::Config < ::Hash
29
+ autoload(:Pathname, 'pathname')
30
+ autoload(:YAML, 'yaml')
31
+
32
+ {
33
+ Reader: 'reader',
34
+ }.each { |k, v| autoload(k, "#{__dir__}/config/#{v}") }
35
+
36
+ # @param basedir [String, Pathname]
37
+ # @param env [Hash{String => String}]
38
+ def initialize(basedir, env: ENV.to_h)
39
+ super().tap do
40
+ @basedir = Pathname.new(basedir).freeze
41
+ @env = self.class.__send__(:env, source: env).freeze
42
+
43
+ self.class.__send__(:call, self.resolve_file, env: env).each { |k, v| self[k.freeze] = v.freeze }
44
+ end.freeze
45
+ end
46
+
47
+ # @return [Hash{String => Object}]
48
+ attr_reader :env
49
+
50
+ # @return [Pathname]
51
+ attr_reader :basedir
52
+
53
+ protected
54
+
55
+ # Resolve path to local config (depending on ``BUNDLE_APP_CONFIG`` value).
56
+ #
57
+ # @return [Pathname]
58
+ def resolve_file
59
+ begin
60
+ 'BUNDLE_APP_CONFIG'.yield_self do |k|
61
+ self.env.fetch(k) { self.class.defaults.fetch(k) }
62
+ end
63
+ end.yield_self do |s|
64
+ Pathname.new(s)
65
+ end.yield_self do |path|
66
+ (path.absolute? ? path : basedir.join(path)).join('config')
67
+ end
68
+ end
69
+
70
+ class << self
71
+ # Default config values (as seen from an empty environment).
72
+ #
73
+ # ```shell
74
+ # rm -rfv ~/.bundle/config .bundle/config
75
+ # env -i $(which bundle) install --standalone
76
+ # cat .bundle/config
77
+ # ```
78
+ #
79
+ # @see Stibium::Bundled::Bundle#bundler_setup
80
+ def defaults
81
+ {
82
+ 'BUNDLE_APP_CONFIG' => '.bundle',
83
+ 'BUNDLE_PATH' => 'bundle',
84
+ }
85
+ end
86
+
87
+ protected
88
+
89
+ # Load config.
90
+ #
91
+ # @param file [Pathname]
92
+ # @param env [Hash{String => String}]
93
+ #
94
+ # @api private
95
+ # @see https://bundler.io/v2.2/bundle_config.html
96
+ #
97
+ # @return [Hash{String => Object}]
98
+ def call(file, env: ENV.to_h)
99
+ # @formatter:off
100
+ self.defaults # 4. Bundler default config
101
+ .merge(self.global_config(env: env)) # 3. Global config
102
+ .merge(self.env(source: env)) # 2. Environmental variables
103
+ .merge(self.read(file, env: env)) # 1. Local config
104
+ .sort.map { |k, v| [k.freeze, v.freeze] }.to_h.freeze
105
+ # @formatter:on
106
+ end
107
+
108
+ # Get global config.
109
+ #
110
+ # @api private
111
+ #
112
+ # @param env [Hash{String => String}]
113
+ #
114
+ # @return [Hash{String => Object}]
115
+ def global_config(env: ENV.to_h)
116
+ env['HOME'].yield_self do |home_path|
117
+ return {} if home_path.nil?
118
+
119
+ Pathname.new(home_path).expand_path.join('.bundle/config').yield_self { |file| self.read(file, env: env) }
120
+ end
121
+ end
122
+
123
+ # Get bundler related environment variables (``/^BUNDLE_.+/``)
124
+ #
125
+ # @param source [Hash{String => String}]
126
+ #
127
+ # @api private
128
+ #
129
+ # @return [Hash{String => Object}]
130
+ def env(source: ENV.to_h)
131
+ source.dup.keep_if { |k, _| /^BUNDLE_.+/ =~ k }
132
+ .transform_keys(&:freeze)
133
+ .transform_values { |v| (v.is_a?(String) ? YAML.safe_load(v) : v).freeze }
134
+ .sort.to_h
135
+ end
136
+
137
+ # Read given config file.
138
+ #
139
+ # @api private
140
+ #
141
+ # @param file [Pathname]
142
+ # @param env [Hash{String => String}]
143
+ #
144
+ # @return [Hash{String => Object}]
145
+ def read(file, env: ENV.to_h)
146
+ Reader.new(env: env).read(file)
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2020-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../config'
10
+
11
+ # Config file reader.
12
+ class Stibium::Bundled::Bundle::Config::Reader
13
+ autoload(:YAML, 'yaml')
14
+
15
+ # @return [Hash{String => String}]
16
+ attr_reader :env
17
+
18
+ def initialize(env: ENV.to_h)
19
+ self.tap do
20
+ @env = env.dup.map { |k, v| [k.freeze, v.freeze] }.to_h.freeze
21
+ end.freeze
22
+ end
23
+
24
+ # @return [Boolean]
25
+ def ignore_config?
26
+ env.key?('BUNDLE_IGNORE_CONFIG')
27
+ end
28
+
29
+ # Read given config file.
30
+ #
31
+ # @param file [Pathname]
32
+ #
33
+ # @return [Hash{String => Object}]
34
+ def read(file)
35
+ scrutinize(file).transform_values { |v| v.is_a?(String) ? YAML.safe_load(v) : v }
36
+ end
37
+
38
+ protected
39
+
40
+ # @api private
41
+ #
42
+ # @param file [Pathname]
43
+ #
44
+ # @raise [RuntimeError]
45
+ # @return [Hash{String => Object}]
46
+ def scrutinize(file)
47
+ return {} if ignore_config?
48
+
49
+ return {} unless file.file? and file.readable?
50
+
51
+ file.read
52
+ .yield_self { |content| YAML.safe_load(content) }
53
+ .yield_self { |result| result.nil? ? {} : result }
54
+ .tap { |result| raise RuntimeError, "Hash expected, got #{result.class}" unless result.is_a?(Hash) }
55
+ end
56
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2020-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../bundle'
10
+
11
+ # Describe vendor directory.
12
+ class Stibium::Bundled::Bundle::Directory
13
+ autoload(:RbConfig, 'rbconfig')
14
+ autoload(:Pathname, 'pathname')
15
+
16
+ # @return [Pathname]
17
+ attr_reader :path
18
+
19
+ # @param path [String, Pathname]
20
+ # @param ruby_config [Hash{Symbol => Object}]
21
+ def initialize(path, ruby_config: {})
22
+ @path = Pathname.new(path).expand_path.freeze
23
+ @ruby_config = {
24
+ engine: RUBY_ENGINE,
25
+ version: RbConfig::CONFIG['ruby_version'],
26
+ }.merge(ruby_config.to_h)
27
+ end
28
+
29
+ # @return [String]
30
+ def to_path
31
+ path.to_path
32
+ end
33
+
34
+ alias to_s to_path
35
+
36
+ # @return [Array<Pathname>]
37
+ def specifications
38
+ [
39
+ [ruby_config.fetch(:engine), ruby_config.fetch(:version), 'specifications', '*.gemspec'],
40
+ [ruby_config.fetch(:engine), ruby_config.fetch(:version), 'bundler', 'gems', '*/*.gemspec'],
41
+ ].map do |parts|
42
+ self.path.join(*parts).yield_self do |s|
43
+ Dir.glob(s).sort.map { |fp| Pathname.new(fp) }.keep_if(&:file?)
44
+ end
45
+ end.flatten.sort
46
+ end
47
+
48
+ protected
49
+
50
+ # @return [Hash{Symbol => Object}]
51
+ attr_reader :ruby_config
52
+ end
@@ -7,11 +7,24 @@
7
7
  # There is NO WARRANTY, to the extent permitted by law.
8
8
 
9
9
  require_relative '../bundled'
10
- require 'kamaze/version'
11
10
 
12
- module Stibium::Bundled
13
- # Version
14
- #
15
- # @type [Kamaze::Version]
16
- VERSION = Kamaze::Version.new.freeze
11
+ Stibium::Bundled.instance_eval do
12
+ autoload(:YAML, 'yaml')
13
+ autoload(:Pathname, 'pathname')
14
+
15
+ Pathname.new(__dir__).join('version.yml').tap do |file|
16
+ YAML.safe_load(file.read).yield_self do |v|
17
+ %w[major minor patch].map { |key| v.fetch(key) }.join('.')
18
+ end.tap do |version|
19
+ lambda do
20
+ require 'kamaze/version'
21
+ rescue LoadError
22
+ # :nocov:
23
+ version
24
+ # :nocov:
25
+ else
26
+ Kamaze::Version.new.freeze
27
+ end.tap { |func| self.const_set(:VERSION, func.call) }
28
+ end
29
+ end
17
30
  end
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  major: 0
3
3
  minor: 0
4
- patch: 1
4
+ patch: 6
5
5
  authors: ['Dimitri Arrigoni']
6
6
  email: 'dimitri@arrigoni.me'
7
- date: '2021-01-11'
7
+ date: '2021-02-22'
8
8
  summary: 'Denote bundle state'
9
- description: 'Denote bundle state, based on conventions.'
9
+ description: 'Denote bundle state and (optionally) load bundler/setup according to the configuration.'
10
10
  homepage: 'https://github.com/SwagDevOps/stibium-bundled'
11
11
  licenses: ['GPL-3.0']
12
12
  license_header: |
metadata CHANGED
@@ -1,39 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stibium-bundled
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Arrigoni
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-11 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: kamaze-version
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.0'
27
- description: Denote bundle state, based on conventions.
11
+ date: 2021-02-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Denote bundle state and (optionally) load bundler/setup according to
14
+ the configuration.
28
15
  email: dimitri@arrigoni.me
29
16
  executables: []
30
17
  extensions: []
31
18
  extra_rdoc_files: []
32
19
  files:
33
20
  - ".yardopts"
21
+ - README.md
34
22
  - lib/stibium-bundled.rb
35
23
  - lib/stibium/bundled.rb
36
24
  - lib/stibium/bundled/bundle.rb
25
+ - lib/stibium/bundled/bundle/config.rb
26
+ - lib/stibium/bundled/bundle/config/reader.rb
27
+ - lib/stibium/bundled/bundle/directory.rb
37
28
  - lib/stibium/bundled/version.rb
38
29
  - lib/stibium/bundled/version.yml
39
30
  homepage: https://github.com/SwagDevOps/stibium-bundled