packs 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 156ed7ab94d5a72f12a96cb0437a3c7ec4dfb3299a56c2bdc3414f588f0497ac
4
- data.tar.gz: 6df13268bafbb79c6b03477ff9981a40a83a18a424e44d51ecf0f42d8689e54b
3
+ metadata.gz: 4f911f00f2059f8b472edbfbe099fe0ee0586bb8426c8593d002fb7a0f4e9924
4
+ data.tar.gz: fc62651af9566195f83822938122f418ed7dd5cab115a3a27ee91fb4416724f9
5
5
  SHA512:
6
- metadata.gz: 0a14fd70f566933916a9047daf9b7201679ace0992d21938de3b33e0d21fa64482f120b5784c2a5166e1cc1fe9d1b8f96238b38e7a1f3d8b684e4adf6937a5de
7
- data.tar.gz: a3214873c063d7f26324eccc7d5ddb206296959cbd0f67747e042014c13633f4186d963337c5cbb14541ff8422ff17dc98183a1eb30417d4d921eceb8d3761a1
6
+ metadata.gz: 4a39af86905f7d639e98938eb83fd45d898a60991cae834d48365da60785dd1dc75b935eced72fa02da1f766382c5cbf817e4337047fbc7b5df66a1ca4853326
7
+ data.tar.gz: d66b67aa6a4b35bccf554390aa5dc23d9ac109dfba0fffe0100ac7d35152afbc6974034c3bbde61d6bcf3278e2a05f28266ea1f3d44614659629beb381704983
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.
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,35 @@
1
+ # typed: strict
2
+
3
+ module Packs
4
+ module Private
5
+ class Configuration < T::Struct
6
+ extend T::Sig
7
+ DEFAULT_PACK_PATHS = T.let([
8
+ 'packs/*',
9
+ 'packs/*/*',
10
+ ], T::Array[String])
11
+
12
+ prop :pack_paths, T::Array[String]
13
+
14
+ sig { returns(Configuration) }
15
+ def self.fetch
16
+ configuration_path = Pathname.new('packs.yml')
17
+ config_hash = configuration_path.exist? ? YAML.load_file('packs.yml') : {}
18
+
19
+ new(
20
+ pack_paths: pack_paths(config_hash),
21
+ )
22
+ end
23
+
24
+ sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[String]) }
25
+ def self.pack_paths(config_hash)
26
+ specified_pack_paths = config_hash['pack_paths']
27
+ if specified_pack_paths.nil?
28
+ DEFAULT_PACK_PATHS.dup
29
+ else
30
+ Array(specified_pack_paths)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ # typed: strict
2
+
3
+ require 'packs/private/configuration'
4
+
5
+ module Packs
6
+ module Private
7
+ extend T::Sig
8
+
9
+ sig { returns(Pathname) }
10
+ def self.root
11
+ Pathname.pwd
12
+ end
13
+ end
14
+
15
+ private_constant :Private
16
+ end
data/lib/packs.rb CHANGED
@@ -1,5 +1,75 @@
1
1
  # typed: strict
2
2
 
3
- # Coming soon...!
3
+ require 'yaml'
4
+ require 'sorbet-runtime'
5
+ require 'packs/pack'
6
+ require 'packs/private'
7
+
4
8
  module Packs
9
+ PACKAGE_FILE = T.let('package.yml'.freeze, String)
10
+ ROOTS = T.let(%w[packs components], T::Array[String])
11
+
12
+ class << self
13
+ extend T::Sig
14
+
15
+ sig { returns(T::Array[Pack]) }
16
+ def all
17
+ packs_by_name.values
18
+ end
19
+
20
+ sig { params(name: String).returns(T.nilable(Pack)) }
21
+ def find(name)
22
+ packs_by_name[name]
23
+ end
24
+
25
+ sig { params(file_path: T.any(Pathname, String)).returns(T.nilable(Pack)) }
26
+ def for_file(file_path)
27
+ path_string = file_path.to_s
28
+ @for_file = T.let(@for_file, T.nilable(T::Hash[String, T.nilable(Pack)]))
29
+ @for_file ||= {}
30
+ @for_file[path_string] ||= all.find { |package| path_string.start_with?("#{package.name}/") || path_string == package.name }
31
+ end
32
+
33
+ sig { void }
34
+ def bust_cache!
35
+ @packs_by_name = nil
36
+ @config = nil
37
+ @for_file = nil
38
+ end
39
+
40
+ sig { returns(Private::Configuration) }
41
+ def config
42
+ @config = T.let(@config, T.nilable(Private::Configuration))
43
+ @config ||= Private::Configuration.fetch
44
+ end
45
+
46
+ sig { params(blk: T.proc.params(arg0: Private::Configuration).void).void }
47
+ def configure(&blk)
48
+ yield(config)
49
+ end
50
+
51
+ private
52
+
53
+ sig { returns(T::Hash[String, Pack]) }
54
+ def packs_by_name
55
+ @packs_by_name = T.let(@packs_by_name, T.nilable(T::Hash[String, Pack]))
56
+ @packs_by_name ||= begin
57
+ all_packs = package_glob_patterns.map do |path|
58
+ Pack.from(path)
59
+ end
60
+
61
+ # We want to match more specific paths first so for_file works correctly.
62
+ sorted_packages = all_packs.sort_by { |package| -package.name.length }
63
+ sorted_packages.to_h { |p| [p.name, p] }
64
+ end
65
+ end
66
+
67
+ sig { returns(T::Array[Pathname]) }
68
+ def package_glob_patterns
69
+ absolute_root = Private.root
70
+ config.pack_paths.flat_map do |pack_path|
71
+ Pathname.glob(absolute_root.join(pack_path).join(PACKAGE_FILE))
72
+ end
73
+ end
74
+ end
5
75
  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.3
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-29 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/pack.rb
122
+ - lib/packs/private.rb
123
+ - lib/packs/private/configuration.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