-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Alex Evanczuk
authored
Dec 21, 2022
1 parent
8fe63d7
commit b4983b1
Showing
13 changed files
with
527 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# The behavior of RuboCop can be controlled via the .rubocop.yml | ||
# configuration file. It makes it possible to enable/disable | ||
# certain cops (checks) and to alter their behavior if they accept | ||
# any parameters. The file can be placed either in your home | ||
# directory or in some project directory. | ||
# | ||
# RuboCop will start looking for the configuration file in the directory | ||
# where the inspected file is and continue its way up to the root directory. | ||
# | ||
# See https://docs.rubocop.org/rubocop/configuration | ||
AllCops: | ||
SuggestExtensions: false | ||
NewCops: enable | ||
Exclude: | ||
- vendor/bundle/**/** | ||
|
||
Metrics/ParameterLists: | ||
Enabled: false | ||
|
||
# This cop is annoying with typed configuration | ||
Style/TrivialAccessors: | ||
Enabled: false | ||
|
||
# This rubocop is annoying when we use interfaces a lot | ||
Lint/UnusedMethodArgument: | ||
Enabled: false | ||
|
||
Gemspec/RequireMFA: | ||
Enabled: false | ||
|
||
Lint/DuplicateBranch: | ||
Enabled: false | ||
|
||
# If is sometimes easier to think about than unless sometimes | ||
Style/NegatedIf: | ||
Enabled: false | ||
|
||
# Disabling for now until it's clearer why we want this | ||
Style/FrozenStringLiteralComment: | ||
Enabled: false | ||
|
||
# It's nice to be able to read the condition first before reading the code within the condition | ||
Style/GuardClause: | ||
Enabled: false | ||
|
||
# | ||
# Leaving length metrics to human judgment for now | ||
# | ||
Metrics/ModuleLength: | ||
Enabled: false | ||
|
||
Layout/LineLength: | ||
Enabled: false | ||
|
||
Metrics/BlockLength: | ||
Enabled: false | ||
|
||
Metrics/MethodLength: | ||
Enabled: false | ||
|
||
Metrics/AbcSize: | ||
Enabled: false | ||
|
||
Metrics/ClassLength: | ||
Enabled: false | ||
|
||
# This doesn't feel useful | ||
Metrics/CyclomaticComplexity: | ||
Enabled: false | ||
|
||
# This doesn't feel useful | ||
Metrics/PerceivedComplexity: | ||
Enabled: false | ||
|
||
# It's nice to be able to read the condition first before reading the code within the condition | ||
Style/IfUnlessModifier: | ||
Enabled: false | ||
|
||
# This leads to code that is not very readable at times (very long lines) | ||
Style/ConditionalAssignment: | ||
Enabled: false | ||
|
||
# For now, we prefer to lean on clean method signatures as documentation. We may change this later. | ||
Style/Documentation: | ||
Enabled: false | ||
|
||
# Sometimes we leave comments in empty else statements intentionally | ||
Style/EmptyElse: | ||
Enabled: false | ||
|
||
# Sometimes we want to more explicitly list out a condition | ||
Style/RedundantCondition: | ||
Enabled: false | ||
|
||
# This leads to code that is not very readable at times (very long lines) | ||
Layout/MultilineMethodCallIndentation: | ||
Enabled: false | ||
|
||
# Blocks across lines are okay sometimes | ||
Style/BlockDelimiters: | ||
Enabled: false | ||
|
||
# This leads to code that is not very readable at times (very long lines) | ||
Layout/FirstArgumentIndentation: | ||
Enabled: false | ||
|
||
# This leads to code that is not very readable at times (very long lines) | ||
Layout/ArgumentAlignment: | ||
Enabled: false | ||
|
||
Style/AccessorGrouping: | ||
Enabled: false | ||
|
||
Style/NumericPredicate: | ||
Enabled: false | ||
|
||
Layout/BlockEndNewline: | ||
Enabled: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,16 @@ | ||
# packs | ||
|
||
Welcome to `packs`! `packs` are a simple ruby specification for an extensible packaging system to help modularize Ruby applications. | ||
|
||
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. | ||
|
||
Here are some example integrations with `packs`: | ||
- [`stimpack`](https://github.com/rubyatscale/stimpack) can be used to integrate `packs` into your `rails` application | ||
- [`rubocop-packs`](https://github.com/rubyatscale/rubocop-packs) contains cops to improve boundaries around `packs` | ||
- [`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 | ||
- [`code_ownership`](https://github.com/rubyatscale/code_ownership) gives your application the capability to determine the owner of a pack | ||
- [`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. | ||
- [`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). | ||
|
||
# How is a pack different from a gem? | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/usr/bin/env ruby | ||
# frozen_string_literal: true | ||
|
||
# | ||
# This file was generated by Bundler. | ||
# | ||
# The application 'rubocop' is installed as part of a gem, and | ||
# this file is here to facilitate running it. | ||
# | ||
|
||
require 'pathname' | ||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', | ||
Pathname.new(__FILE__).realpath) | ||
|
||
bundle_binstub = File.expand_path('bundle', __dir__) | ||
|
||
if File.file?(bundle_binstub) | ||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ | ||
load(bundle_binstub) | ||
else | ||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. | ||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") | ||
end | ||
end | ||
|
||
require 'rubygems' | ||
require 'bundler/setup' | ||
|
||
load Gem.bin_path('rubocop', 'rubocop') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,68 @@ | ||
# typed: strict | ||
|
||
# Coming soon...! | ||
require 'yaml' | ||
require 'sorbet-runtime' | ||
require 'packs/pack' | ||
require 'packs/configuration' | ||
require 'packs/private' | ||
|
||
module Packs | ||
PACKAGE_FILE = T.let('package.yml'.freeze, String) | ||
ROOTS = T.let(%w[packs components], T::Array[String]) | ||
|
||
class << self | ||
extend T::Sig | ||
|
||
sig { returns(T::Array[Pack]) } | ||
def all | ||
packs_by_name.values | ||
end | ||
|
||
sig { params(name: String).returns(T.nilable(Pack)) } | ||
def find(name) | ||
packs_by_name[name] | ||
end | ||
|
||
sig { params(file_path: T.any(Pathname, String)).returns(T.nilable(Pack)) } | ||
def for_file(file_path) | ||
path_string = file_path.to_s | ||
@for_file = T.let(@for_file, T.nilable(T::Hash[String, T.nilable(Pack)])) | ||
@for_file ||= {} | ||
@for_file[path_string] ||= all.find { |package| path_string.start_with?("#{package.name}/") || path_string == package.name } | ||
end | ||
|
||
sig { void } | ||
def bust_cache! | ||
@packs_by_name = nil | ||
@config = nil | ||
@for_file = nil | ||
end | ||
|
||
private | ||
|
||
sig { returns(T::Hash[String, Pack]) } | ||
def packs_by_name | ||
@packs_by_name = T.let(@packs_by_name, T.nilable(T::Hash[String, Pack])) | ||
@packs_by_name ||= begin | ||
all_packs = package_glob_patterns.map do |path| | ||
Pack.from(path) | ||
end | ||
|
||
# We want to match more specific paths first so for_file works correctly. | ||
sorted_packages = all_packs.sort_by { |package| -package.name.length } | ||
sorted_packages.to_h { |p| [p.name, p] } | ||
end | ||
end | ||
|
||
sig { returns(T::Array[Pathname]) } | ||
def package_glob_patterns | ||
config.roots.flat_map do |root| | ||
absolute_root = Private.root.join(root) | ||
[ | ||
*absolute_root.glob("*/#{PACKAGE_FILE}"), | ||
*absolute_root.glob("*/*/#{PACKAGE_FILE}") | ||
] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# typed: strict | ||
|
||
module Packs | ||
class Configuration | ||
extend T::Sig | ||
|
||
sig { params(roots: T::Array[String]).void } | ||
attr_writer :roots | ||
|
||
sig { void } | ||
def initialize | ||
@roots = T.let(ROOTS, T::Array[String]) | ||
end | ||
|
||
sig { returns(T::Array[Pathname]) } | ||
def roots | ||
@roots.map do |root| | ||
Pathname.new(root) | ||
end | ||
end | ||
end | ||
|
||
class << self | ||
extend T::Sig | ||
|
||
sig { returns(Configuration) } | ||
def config | ||
@config = T.let(@config, T.nilable(Configuration)) | ||
@config ||= Configuration.new | ||
end | ||
|
||
sig { params(blk: T.proc.params(arg0: Configuration).void).void } | ||
def configure(&blk) | ||
yield(config) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# typed: strict | ||
|
||
module Packs | ||
class Pack < T::Struct | ||
extend T::Sig | ||
|
||
const :name, String | ||
const :path, Pathname | ||
const :relative_path, Pathname | ||
const :raw_hash, T::Hash[T.untyped, T.untyped] | ||
|
||
sig { params(package_yml_absolute_path: Pathname).returns(Pack) } | ||
def self.from(package_yml_absolute_path) | ||
package_loaded_yml = YAML.load_file(package_yml_absolute_path) | ||
path = package_yml_absolute_path.dirname | ||
relative_path = path.relative_path_from(Private.root) | ||
package_name = relative_path.cleanpath.to_s | ||
|
||
Pack.new( | ||
name: package_name, | ||
path: path, | ||
relative_path: relative_path, | ||
raw_hash: package_loaded_yml || {} | ||
) | ||
end | ||
|
||
sig { params(relative: T::Boolean).returns(Pathname) } | ||
def yml(relative: true) | ||
path_to_use = relative ? relative_path : path | ||
path_to_use.join(PACKAGE_FILE).cleanpath | ||
end | ||
|
||
sig { returns(String) } | ||
def last_name | ||
relative_path.basename.to_s | ||
end | ||
|
||
sig { returns(T::Hash[T.untyped, T.untyped]) } | ||
def metadata | ||
raw_hash['metadata'] || {} | ||
end | ||
end | ||
end |
Oops, something went wrong.