packs 0.0.1 → 0.0.2

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: 156ed7ab94d5a72f12a96cb0437a3c7ec4dfb3299a56c2bdc3414f588f0497ac
4
- data.tar.gz: 6df13268bafbb79c6b03477ff9981a40a83a18a424e44d51ecf0f42d8689e54b
3
+ metadata.gz: 29e18f23de09397b4441c88789b231d1226bd68bea5d0fce16655d0367f93b9b
4
+ data.tar.gz: bfd5b5aefd4de2aa8b126accd52c44a980ca1302a57c49d6faf37a969ca2d1f5
5
5
  SHA512:
6
- metadata.gz: 0a14fd70f566933916a9047daf9b7201679ace0992d21938de3b33e0d21fa64482f120b5784c2a5166e1cc1fe9d1b8f96238b38e7a1f3d8b684e4adf6937a5de
7
- data.tar.gz: a3214873c063d7f26324eccc7d5ddb206296959cbd0f67747e042014c13633f4186d963337c5cbb14541ff8422ff17dc98183a1eb30417d4d921eceb8d3761a1
6
+ metadata.gz: 29a0c8a277e0ae42061219e86ab7371dcd014e3649e3728db0d166f98c30ad430ad04a9d8cec82d862e34e075a12dbaf4ae4b96e4f77e97addfc01881762cf8f
7
+ data.tar.gz: c9dccdac635c403f4a0ec2f305bf9947b7ca2b96ef943ae2088888e3b2a553743f19baae48b0451c574b69abda8de2c71275de6ce6637767640a0e6f431479a2
data/README.md CHANGED
@@ -1 +1,16 @@
1
1
  # packs
2
+
3
+ Welcome to `packs`! `packs` are a simple ruby specification for an extensible packaging system to help modularize Ruby applications.
4
+
5
+ A `pack` (also called `package`) is a folder of Ruby code with a `package.yml` at the root that is intended to represent a well-modularized domain, and the rest of the [rubyatscale](https://github.com/rubyatscale) ecosystem is intended to help make the boundaries between a pack and any other more clear.
6
+
7
+ Here are some example integrations with `packs`:
8
+ - [`stimpack`](https://github.com/rubyatscale/stimpack) can be used to integrate `packs` into your `rails` application
9
+ - [`rubocop-packs`](https://github.com/rubyatscale/rubocop-packs) contains cops to improve boundaries around `packs`
10
+ - [`packwerk`](https://github.com/Shopify/packwerk) and [`packwerk-extensions`](https://github.com/rubyatscale/packwerk-extensions) help you describe and constrain your package graph in terms of dependencies between packs and pack public API
11
+ - [`code_ownership`](https://github.com/rubyatscale/code_ownership) gives your application the capability to determine the owner of a pack
12
+ - [`use_packs`](https://github.com/rubyatscale/use_packs) gives a CLI, `bin/packs`, that makes it easy to create new packs, move files between packs, and more.
13
+ - [`pack_stats`](https://github.com/rubyatscale/pack_stats) makes it easy to send metrics about pack adoption and modularization to your favorite metrics provider, such as DataDog (which has built-in support).
14
+
15
+ # How is a pack different from a gem?
16
+ A ruby [`gem`](https://guides.rubygems.org/what-is-a-gem/) is the Ruby community solution for packaging and distributing Ruby code. A gem is a great place to start new projects, and a great end state for code that's been extracted from an existing codebase. `packs` are intended to help gradually modularize an application that has some conceptual boundaries, but is not yet ready to be factored into gems.
@@ -0,0 +1,37 @@
1
+ # typed: strict
2
+
3
+ module Packs
4
+ class Configuration
5
+ extend T::Sig
6
+
7
+ sig { params(roots: T::Array[String]).void }
8
+ attr_writer :roots
9
+
10
+ sig { void }
11
+ def initialize
12
+ @roots = T.let(ROOTS, T::Array[String])
13
+ end
14
+
15
+ sig { returns(T::Array[Pathname]) }
16
+ def roots
17
+ @roots.map do |root|
18
+ Pathname.new(root)
19
+ end
20
+ end
21
+ end
22
+
23
+ class << self
24
+ extend T::Sig
25
+
26
+ sig { returns(Configuration) }
27
+ def config
28
+ @config = T.let(@config, T.nilable(Configuration))
29
+ @config ||= Configuration.new
30
+ end
31
+
32
+ sig { params(blk: T.proc.params(arg0: Configuration).void).void }
33
+ def configure(&blk)
34
+ yield(config)
35
+ end
36
+ end
37
+ end
data/lib/packs/pack.rb ADDED
@@ -0,0 +1,43 @@
1
+ # typed: strict
2
+
3
+ module Packs
4
+ class Pack < T::Struct
5
+ extend T::Sig
6
+
7
+ const :name, String
8
+ const :path, Pathname
9
+ const :relative_path, Pathname
10
+ const :raw_hash, T::Hash[T.untyped, T.untyped]
11
+
12
+ sig { params(package_yml_absolute_path: Pathname).returns(Pack) }
13
+ def self.from(package_yml_absolute_path)
14
+ package_loaded_yml = YAML.load_file(package_yml_absolute_path)
15
+ path = package_yml_absolute_path.dirname
16
+ relative_path = path.relative_path_from(Private.root)
17
+ package_name = relative_path.cleanpath.to_s
18
+
19
+ Pack.new(
20
+ name: package_name,
21
+ path: path,
22
+ relative_path: relative_path,
23
+ raw_hash: package_loaded_yml || {}
24
+ )
25
+ end
26
+
27
+ sig { params(relative: T::Boolean).returns(Pathname) }
28
+ def yml(relative: true)
29
+ path_to_use = relative ? relative_path : path
30
+ path_to_use.join(PACKAGE_FILE).cleanpath
31
+ end
32
+
33
+ sig { returns(String) }
34
+ def last_name
35
+ relative_path.basename.to_s
36
+ end
37
+
38
+ sig { returns(T::Hash[T.untyped, T.untyped]) }
39
+ def metadata
40
+ raw_hash['metadata'] || {}
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+
3
+ module Packs
4
+ module Private
5
+ extend T::Sig
6
+
7
+ sig { returns(Pathname) }
8
+ def self.root
9
+ Pathname.pwd
10
+ end
11
+ end
12
+
13
+ private_constant :Private
14
+ end
data/lib/packs.rb CHANGED
@@ -1,5 +1,68 @@
1
1
  # typed: strict
2
2
 
3
- # Coming soon...!
3
+ require 'yaml'
4
+ require 'sorbet-runtime'
5
+ require 'packs/pack'
6
+ require 'packs/configuration'
7
+ require 'packs/private'
8
+
4
9
  module Packs
10
+ PACKAGE_FILE = T.let('package.yml'.freeze, String)
11
+ ROOTS = T.let(%w[packs components], T::Array[String])
12
+
13
+ class << self
14
+ extend T::Sig
15
+
16
+ sig { returns(T::Array[Pack]) }
17
+ def all
18
+ packs_by_name.values
19
+ end
20
+
21
+ sig { params(name: String).returns(T.nilable(Pack)) }
22
+ def find(name)
23
+ packs_by_name[name]
24
+ end
25
+
26
+ sig { params(file_path: T.any(Pathname, String)).returns(T.nilable(Pack)) }
27
+ def for_file(file_path)
28
+ path_string = file_path.to_s
29
+ @for_file = T.let(@for_file, T.nilable(T::Hash[String, T.nilable(Pack)]))
30
+ @for_file ||= {}
31
+ @for_file[path_string] ||= all.find { |package| path_string.start_with?("#{package.name}/") || path_string == package.name }
32
+ end
33
+
34
+ sig { void }
35
+ def bust_cache!
36
+ @packs_by_name = nil
37
+ @config = nil
38
+ @for_file = nil
39
+ end
40
+
41
+ private
42
+
43
+ sig { returns(T::Hash[String, Pack]) }
44
+ def packs_by_name
45
+ @packs_by_name = T.let(@packs_by_name, T.nilable(T::Hash[String, Pack]))
46
+ @packs_by_name ||= begin
47
+ all_packs = package_glob_patterns.map do |path|
48
+ Pack.from(path)
49
+ end
50
+
51
+ # We want to match more specific paths first so for_file works correctly.
52
+ sorted_packages = all_packs.sort_by { |package| -package.name.length }
53
+ sorted_packages.to_h { |p| [p.name, p] }
54
+ end
55
+ end
56
+
57
+ sig { returns(T::Array[Pathname]) }
58
+ def package_glob_patterns
59
+ config.roots.flat_map do |root|
60
+ absolute_root = Private.root.join(root)
61
+ [
62
+ *absolute_root.glob("*/#{PACKAGE_FILE}"),
63
+ *absolute_root.glob("*/*/#{PACKAGE_FILE}")
64
+ ]
65
+ end
66
+ end
67
+ end
5
68
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gusto Engineers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-05 00:00:00.000000000 Z
11
+ date: 2022-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: sorbet
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -104,8 +118,9 @@ extra_rdoc_files: []
104
118
  files:
105
119
  - README.md
106
120
  - lib/packs.rb
107
- - sorbet/config
108
- - sorbet/rbi/todo.rbi
121
+ - lib/packs/configuration.rb
122
+ - lib/packs/pack.rb
123
+ - lib/packs/private.rb
109
124
  homepage: https://github.com/rubyatscale/packs
110
125
  licenses:
111
126
  - MIT
@@ -129,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
144
  - !ruby/object:Gem::Version
130
145
  version: '0'
131
146
  requirements: []
132
- rubygems_version: 3.3.7
147
+ rubygems_version: 3.1.6
133
148
  signing_key:
134
149
  specification_version: 4
135
150
  summary: Packs are the specification for gradual modularization in the `rubyatscale`
data/sorbet/config DELETED
@@ -1,3 +0,0 @@
1
- --dir
2
- .
3
- --ignore=/vendor/bundle
data/sorbet/rbi/todo.rbi DELETED
@@ -1,5 +0,0 @@
1
- # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2
- # srb rbi todo
3
-
4
- # typed: strong
5
- module ::RSpec; end