foobara 0.0.1 → 0.0.3
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/projects/command/src/concerns/domain_mappers.rb +23 -10
- data/projects/command/src/concerns/reflection.rb +1 -1
- data/projects/command_connectors_http/src/http/commands/help/templates/entity.html.erb +11 -1
- data/projects/command_connectors_http/src/http/commands/help/templates/model.html.erb +8 -1
- data/projects/command_connectors_http/src/http/response.rb +2 -2
- data/projects/command_connectors_http/src/http.rb +9 -0
- data/projects/domain/src/domain_mapper/registry.rb +31 -0
- data/projects/domain/src/domain_module_extension.rb +1 -14
- data/projects/foobara/lib/foobara/all.rb +0 -3
- data/projects/manifest/src/foobara/manifest/entity.rb +4 -0
- data/projects/manifest/src/foobara/manifest/model.rb +4 -0
- data/projects/manifest/src/foobara/manifest/type.rb +1 -1
- data/projects/manifest/src/foobara/manifest/type_declaration.rb +1 -1
- data/projects/type_declarations/src/type_declaration_handler.rb +1 -1
- data/projects/types/src/type.rb +2 -2
- data/projects/value/src/processor/casting.rb +2 -2
- data/projects/value/src/processor/multi.rb +2 -2
- data/projects/value/src/processor/selection.rb +2 -2
- metadata +5 -15
- data/.rspec +0 -5
- data/.rubocop.yml +0 -20
- data/.ruby-version +0 -1
- data/DECISION_LOG.md +0 -220
- data/Guardfile +0 -9
- data/Rakefile +0 -10
- data/concepts.md +0 -153
- data/projects/version/lib/foobara/version.rb +0 -4
- data/projects/version/src/version.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c67b545a741174d59b5a74553449d32169d2745b33824ad14ee21e4dac7085b
|
4
|
+
data.tar.gz: 1e54750375fe79b83ee0bbf08e460021193124e5f7f661c4eef39afd53c3573b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18d0063f27c3c708b30603091ddaaba2bb11ad864d6902b705f0b120ba64ed32f33f64023561a11086e3cf266cf426b927deefc44e173d625156e6aa4d2c9a19
|
7
|
+
data.tar.gz: 84f34116a5033ae5c2f34c6e408520cb61a2b0efbedbb59b1b07792c35992c1622153a4b254c8c5c4bd3782b6a22c0a04ec828160f3a0c11e0729871a160ccc7
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.0.3] - 2024-08-15
|
2
|
+
|
3
|
+
- Do not automatically try to map subcommand types to calling command result type
|
4
|
+
- Add some crude help info for models in http connector
|
5
|
+
|
6
|
+
## [0.0.2] - 2024-06-20
|
7
|
+
|
8
|
+
- Make sure content-type is json if we are json serializing an HTTP response
|
9
|
+
|
1
10
|
## [0.0.1] - 2024-05-31
|
2
11
|
|
3
12
|
Very very alpha alpha release for convenience of demoing the project.
|
@@ -4,22 +4,35 @@ module Foobara
|
|
4
4
|
module DomainMappers
|
5
5
|
include Concern
|
6
6
|
|
7
|
-
def run_mapped_subcommand!(subcommand_class,
|
7
|
+
def run_mapped_subcommand!(subcommand_class, *args)
|
8
|
+
unmapped_inputs, has_result_type, result_type =
|
9
|
+
case args.size
|
10
|
+
when 1
|
11
|
+
[args.first]
|
12
|
+
when 2
|
13
|
+
[args[1], true, args[0]]
|
14
|
+
else
|
15
|
+
# :nocov:
|
16
|
+
raise ArgumentError,
|
17
|
+
"Wrong number of arguments: (#{args.size}. Expected 2 or 3 argument."
|
18
|
+
# :nocov:
|
19
|
+
end
|
20
|
+
|
8
21
|
inputs = domain_map!(unmapped_inputs, to: subcommand_class, strict: true)
|
9
22
|
|
10
23
|
result = run_subcommand!(subcommand_class, inputs)
|
11
24
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
25
|
+
if has_result_type
|
26
|
+
result_mapper = self.class.domain.foobara_domain_mapper_registry.lookup!(
|
27
|
+
from: result,
|
28
|
+
to: result_type,
|
29
|
+
strict: true
|
30
|
+
)
|
17
31
|
|
18
|
-
|
19
|
-
result_mapper.map(result)
|
20
|
-
else
|
21
|
-
result
|
32
|
+
result = result_mapper.map(result)
|
22
33
|
end
|
34
|
+
|
35
|
+
result
|
23
36
|
end
|
24
37
|
|
25
38
|
def domain_map(...)
|
@@ -1 +1,11 @@
|
|
1
|
-
|
1
|
+
<h1><%= full_entity_name %></h1>
|
2
|
+
<p><%= description %></p>
|
3
|
+
|
4
|
+
<h2>Attributes</h2>
|
5
|
+
<%= render_html_list(attributes_type) %>
|
6
|
+
|
7
|
+
<h2>Primary Key</h2>
|
8
|
+
<%= primary_key_attribute %>
|
9
|
+
|
10
|
+
<h2>Possible Errors</h2>
|
11
|
+
<%= render_html_list(possible_errors) %>
|
@@ -60,6 +60,15 @@ module Foobara
|
|
60
60
|
def headers_for(request)
|
61
61
|
response_headers = request.response_headers
|
62
62
|
|
63
|
+
if response_headers.nil? || !response_headers.key?("content-type")
|
64
|
+
if request.command.respond_to?(:serialize_result)
|
65
|
+
# TODO: we should ask the request this not the command.
|
66
|
+
if request.command.serializers.include?(Serializers::JsonSerializer)
|
67
|
+
response_headers = (response_headers || {}).merge("content-type" => "application/json")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
63
72
|
if response_headers
|
64
73
|
static_headers.merge(response_headers)
|
65
74
|
else
|
@@ -1,5 +1,30 @@
|
|
1
1
|
module Foobara
|
2
2
|
class DomainMapper
|
3
|
+
class NoDomainMapperFoundError < StandardError
|
4
|
+
attr_accessor :value, :from, :to, :has_value
|
5
|
+
|
6
|
+
def initialize(from, to, **opts)
|
7
|
+
valid_keys = [:value]
|
8
|
+
invalid_keys = opts.keys - [:value]
|
9
|
+
|
10
|
+
if invalid_keys.any?
|
11
|
+
# :nocov:
|
12
|
+
raise ArgumentError, "Invalid keys: #{invalid_keys.join(", ")}. expected one of: #{valid_keys.join(", ")}"
|
13
|
+
# :nocov:
|
14
|
+
end
|
15
|
+
|
16
|
+
if opts.key?(:value)
|
17
|
+
self.has_value = true
|
18
|
+
self.value = opts[:value]
|
19
|
+
end
|
20
|
+
|
21
|
+
self.from = from
|
22
|
+
self.to = to
|
23
|
+
|
24
|
+
super("No domain mapper found for #{value}. from: #{from}. to: #{to}.")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
3
28
|
class Registry
|
4
29
|
class AmbiguousDomainMapperError < StandardError
|
5
30
|
attr_accessor :candidates, :from, :to
|
@@ -17,6 +42,12 @@ module Foobara
|
|
17
42
|
mappers << mapper
|
18
43
|
end
|
19
44
|
|
45
|
+
def lookup!(from: nil, to: nil, strict: false)
|
46
|
+
result = lookup(from:, to:, strict:)
|
47
|
+
|
48
|
+
result || raise(NoDomainMapperFoundError.new(from, to))
|
49
|
+
end
|
50
|
+
|
20
51
|
def lookup(from: nil, to: nil, strict: false)
|
21
52
|
candidates = mappers.select do |mapper|
|
22
53
|
mapper.applicable?(from, to)
|
@@ -4,18 +4,6 @@ module Foobara
|
|
4
4
|
class AlreadyRegisteredError < StandardError; end
|
5
5
|
class CannotSetTypeConstantError < StandardError; end
|
6
6
|
|
7
|
-
class NoDomainMapperFoundError < StandardError
|
8
|
-
attr_accessor :value, :from, :to
|
9
|
-
|
10
|
-
def initialize(value, from, to)
|
11
|
-
self.value = value
|
12
|
-
self.from = from
|
13
|
-
self.to = to
|
14
|
-
|
15
|
-
super("No domain mapper found for #{value}. from: #{from}. to: #{to}.")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
7
|
class << self
|
20
8
|
def global
|
21
9
|
GlobalDomain
|
@@ -165,9 +153,8 @@ module Foobara
|
|
165
153
|
|
166
154
|
def foobara_domain_map!(value, from: value, to: nil, strict: false)
|
167
155
|
mapper = foobara_domain_mapper_registry.lookup(from:, to:, strict:)
|
168
|
-
|
169
156
|
unless mapper
|
170
|
-
raise NoDomainMapperFoundError.new(
|
157
|
+
raise Foobara::DomainMapper::NoDomainMapperFoundError.new(from, to, value:)
|
171
158
|
end
|
172
159
|
|
173
160
|
mapper.call(value)
|
@@ -25,6 +25,10 @@ module Foobara
|
|
25
25
|
super - [primary_key_name]
|
26
26
|
end
|
27
27
|
|
28
|
+
def full_entity_name
|
29
|
+
full_model_name
|
30
|
+
end
|
31
|
+
|
28
32
|
def associations
|
29
33
|
@associations ||= self[:associations].to_h do |path_key, type_name|
|
30
34
|
[path_key.to_sym, Type.new(root_manifest, [:type, type_name])]
|
@@ -94,7 +94,7 @@ module Foobara
|
|
94
94
|
|
95
95
|
def process_value(raw_type_declaration)
|
96
96
|
# TODO: deep_dup this again??
|
97
|
-
super
|
97
|
+
super.tap do |type_outcome|
|
98
98
|
if type_outcome.success?
|
99
99
|
type_outcome.result.raw_declaration_data = raw_type_declaration
|
100
100
|
end
|
data/projects/types/src/type.rb
CHANGED
@@ -35,7 +35,7 @@ module Foobara
|
|
35
35
|
attr_reader :type_symbol
|
36
36
|
|
37
37
|
def initialize(
|
38
|
-
|
38
|
+
*,
|
39
39
|
target_classes:,
|
40
40
|
base_type:,
|
41
41
|
description: nil,
|
@@ -63,7 +63,7 @@ module Foobara
|
|
63
63
|
self.name = name
|
64
64
|
self.target_classes = Util.array(target_classes)
|
65
65
|
|
66
|
-
super(
|
66
|
+
super(*, **opts.merge(processors:, prioritize: false))
|
67
67
|
|
68
68
|
validate_processors!
|
69
69
|
end
|
@@ -39,7 +39,7 @@ module Foobara
|
|
39
39
|
|
40
40
|
attr_accessor :target_classes
|
41
41
|
|
42
|
-
def initialize(
|
42
|
+
def initialize(*, casters:, target_classes: nil)
|
43
43
|
self.target_classes = Util.array(target_classes)
|
44
44
|
|
45
45
|
processors = [
|
@@ -47,7 +47,7 @@ module Foobara
|
|
47
47
|
*casters
|
48
48
|
]
|
49
49
|
|
50
|
-
super(
|
50
|
+
super(*, processors:)
|
51
51
|
end
|
52
52
|
|
53
53
|
def needs_cast?(value)
|
@@ -10,10 +10,10 @@ module Foobara
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(
|
13
|
+
def initialize(*, processors: [], prioritize: true)
|
14
14
|
self.prioritize = prioritize
|
15
15
|
self.processors = prioritize ? processors.sort_by(&:priority) : processors
|
16
|
-
super(*
|
16
|
+
super(*)
|
17
17
|
end
|
18
18
|
|
19
19
|
def processor_names
|
@@ -18,9 +18,9 @@ module Foobara
|
|
18
18
|
|
19
19
|
attr_accessor :enforce_unique
|
20
20
|
|
21
|
-
def initialize(
|
21
|
+
def initialize(*, enforce_unique: true, **)
|
22
22
|
self.enforce_unique = enforce_unique
|
23
|
-
super(
|
23
|
+
super(*, **)
|
24
24
|
end
|
25
25
|
|
26
26
|
# TODO: move applies_message usage here from casting processor
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: foobara-util
|
@@ -32,17 +32,10 @@ executables: []
|
|
32
32
|
extensions: []
|
33
33
|
extra_rdoc_files: []
|
34
34
|
files:
|
35
|
-
- ".rspec"
|
36
|
-
- ".rubocop.yml"
|
37
|
-
- ".ruby-version"
|
38
35
|
- CHANGELOG.md
|
39
|
-
- DECISION_LOG.md
|
40
|
-
- Guardfile
|
41
36
|
- LICENSE-AGPL.txt
|
42
37
|
- LICENSE.txt
|
43
38
|
- README.md
|
44
|
-
- Rakefile
|
45
|
-
- concepts.md
|
46
39
|
- projects/builtin_types/lib/foobara/builtin_types.rb
|
47
40
|
- projects/builtin_types/src/README.md
|
48
41
|
- projects/builtin_types/src/array/casters/arrayable.rb
|
@@ -385,8 +378,6 @@ files:
|
|
385
378
|
- projects/value/src/processor/selection.rb
|
386
379
|
- projects/value/src/transformer.rb
|
387
380
|
- projects/value/src/validator.rb
|
388
|
-
- projects/version/lib/foobara/version.rb
|
389
|
-
- projects/version/src/version.rb
|
390
381
|
- projects/weak_object_set/lib/foobara/weak_object_set.rb
|
391
382
|
- projects/weak_object_set/src/weak_object_set.rb
|
392
383
|
homepage: https://github.com/foobara/foobara
|
@@ -397,7 +388,7 @@ metadata:
|
|
397
388
|
source_code_uri: https://github.com/foobara/foobara
|
398
389
|
changelog_uri: https://github.com/foobara/foobara/CHANGELOG.md
|
399
390
|
rubygems_mfa_required: 'true'
|
400
|
-
post_install_message:
|
391
|
+
post_install_message:
|
401
392
|
rdoc_options: []
|
402
393
|
require_paths:
|
403
394
|
- "./projects/builtin_types/lib"
|
@@ -424,7 +415,6 @@ require_paths:
|
|
424
415
|
- "./projects/type_declarations/lib"
|
425
416
|
- "./projects/types/lib"
|
426
417
|
- "./projects/value/lib"
|
427
|
-
- "./projects/version/lib"
|
428
418
|
- "./projects/weak_object_set/lib"
|
429
419
|
required_ruby_version: !ruby/object:Gem::Requirement
|
430
420
|
requirements:
|
@@ -438,7 +428,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
438
428
|
version: '0'
|
439
429
|
requirements: []
|
440
430
|
rubygems_version: 3.4.10
|
441
|
-
signing_key:
|
431
|
+
signing_key:
|
442
432
|
specification_version: 4
|
443
433
|
summary: Implements command pattern for encapsulating and managing domain complexity
|
444
434
|
as well as many supporting libraries including entities.
|
data/.rspec
DELETED
data/.rubocop.yml
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
AllCops:
|
2
|
-
TargetRubyVersion: 3.2
|
3
|
-
NewCops: enable
|
4
|
-
|
5
|
-
inherit_gem:
|
6
|
-
foobara-rubocop-rules:
|
7
|
-
- rules/*
|
8
|
-
|
9
|
-
Naming/FileName:
|
10
|
-
ExpectMatchingDefinition: true
|
11
|
-
CheckDefinitionPathHierarchy: true
|
12
|
-
Exclude:
|
13
|
-
- spec/lib/**/*
|
14
|
-
- spec/**/*
|
15
|
-
- bin/*
|
16
|
-
CheckDefinitionPathHierarchyRoots:
|
17
|
-
- src
|
18
|
-
- extensions
|
19
|
-
- spec
|
20
|
-
IgnoreExecutableScripts: true
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
3.2.2
|
data/DECISION_LOG.md
DELETED
@@ -1,220 +0,0 @@
|
|
1
|
-
This document is intended to document the rationale behind certain key decisions
|
2
|
-
|
3
|
-
<!-- TOC -->
|
4
|
-
* [2024-05-30 Dual-license under Apache-2.0 OR MIT](#2024-05-30-dual-license-under-apache-20-or-mit)
|
5
|
-
* [Decision](#decision)
|
6
|
-
* [Rationale](#rationale)
|
7
|
-
* [Why MIT](#why-mit)
|
8
|
-
* [Why Apache-2.0](#why-apache-20)
|
9
|
-
* [Why Apache-2.0 OR MIT](#why-apache-20-or-mit)
|
10
|
-
* [Other licenses that were contenders](#other-licenses-that-were-contenders)
|
11
|
-
* [Other concern about the murky state of generative AI and copyright implications](#other-concern-about-the-murky-state-of-generative-ai-and-copyright-implications)
|
12
|
-
* [[RETRACTED] 2024-05-19 License under user choice of 3 licenses](#retracted-2024-05-19-license-under-user-choice-of-3-licenses)
|
13
|
-
* [Decision](#decision-1)
|
14
|
-
* [Rationale](#rationale-1)
|
15
|
-
* [Why MIT OR Apache 2.0](#why-mit-or-apache-20)
|
16
|
-
* [Why MIT is attractive](#why-mit-is-attractive)
|
17
|
-
* [Why Apache 2.0 is attractive](#why-apache-20-is-attractive)
|
18
|
-
* [Why MIT OR Apache 2.0 is attractive](#why-mit-or-apache-20-is-attractive)
|
19
|
-
* [Why OR MPL 2.0](#why-or-mpl-20)
|
20
|
-
* [why MPL 2.0 is attractive](#why-mpl-20-is-attractive)
|
21
|
-
* [Why OR MPL 2.0, ie, why is MPL 2.0 scary](#why-or-mpl-20-ie-why-is-mpl-20-scary)
|
22
|
-
* [What would have been an ideal license?](#what-would-have-been-an-ideal-license)
|
23
|
-
* [Conclusion](#conclusion)
|
24
|
-
<!-- TOC -->
|
25
|
-
|
26
|
-
# 2024-05-31 Temporarily release under AGPLv3
|
27
|
-
|
28
|
-
## Decision
|
29
|
-
|
30
|
-
Adopting a very restrictive license temporarily
|
31
|
-
|
32
|
-
## Rationale
|
33
|
-
|
34
|
-
Unblocks demos that benefit from use of rubygems while buying time to officially finalize a licensing decision.
|
35
|
-
|
36
|
-
# [TENTATIVE] 2024-05-30 Dual-license under Apache-2.0 OR MIT
|
37
|
-
|
38
|
-
## Decision
|
39
|
-
|
40
|
-
Release gems in the foobara org under Apache-2.0 OR MIT.
|
41
|
-
|
42
|
-
## Rationale
|
43
|
-
|
44
|
-
### Why MIT
|
45
|
-
|
46
|
-
* Typical license of the Ruby ecosystem
|
47
|
-
* High-compatibility with other software licenses.
|
48
|
-
|
49
|
-
### Why Apache-2.0
|
50
|
-
|
51
|
-
* Robust
|
52
|
-
* Includes patent grants
|
53
|
-
|
54
|
-
### Why Apache-2.0 OR MIT
|
55
|
-
|
56
|
-
* Maximizes contexts in which Foobara can unambiguously be used without
|
57
|
-
much overhead or confusion.
|
58
|
-
* Reduces needs to debate less typical licensing options with users
|
59
|
-
or contributors.
|
60
|
-
* Reduces need to relicense later for adoption's sake.
|
61
|
-
* Just Apache-2.0 results in incompatibility with GPLv2
|
62
|
-
* Just MIT does not explicitly extend patent grants.
|
63
|
-
|
64
|
-
A thought... By choosing this combination instead of MPL-2.0, then it's not
|
65
|
-
possible to use Foobara in a GPLv2 app without receiving a patent grant from the
|
66
|
-
MIT license. However, my understanding is that such a user does at least know that
|
67
|
-
all contributors have granted any patents in their contributed code to the Foobara
|
68
|
-
project itself by meeting the requirements of both licenses in order to contribute.
|
69
|
-
|
70
|
-
### Other licenses that were contenders
|
71
|
-
|
72
|
-
* MPL-2.0
|
73
|
-
* Pros:
|
74
|
-
* Robust
|
75
|
-
* Compatible with GPLv2 and includes patent grants, eliminating the need to dual-license
|
76
|
-
* Cons:
|
77
|
-
* Not typical in the Ruby ecosystem and would result in conversations among contributors and users.
|
78
|
-
* Could also potentially impact adoption negatively though I don't think it logically should.
|
79
|
-
* Neutral:
|
80
|
-
* The copyleft aspects of MPL-2.0 seem fair while still being quite permissive. However, likely irrelevant because:
|
81
|
-
* These types of projects are typically used as unmodified libraries distributed by rubygems.
|
82
|
-
* When there is a modification, there's not much incentive not to share those improvements. It is
|
83
|
-
a hassle to manage a private fork and easier to just upstream improvements to avoid
|
84
|
-
that hassle.
|
85
|
-
* Even in the case of a private fork, typically the code winds up being used in some network service
|
86
|
-
and not "distributed" and so the copyleft is irrelevant in these common usage patterns
|
87
|
-
* File-level aspect.
|
88
|
-
* Receiving a copy of the modified code is generally the normal usage pattern since it's
|
89
|
-
an interpreted language. There are some tools for encoding but usually Ruby is interpreted from the source,
|
90
|
-
however, the typical pattern is to receive the code.
|
91
|
-
* Also means static-linking stuff is not relevant
|
92
|
-
* Ruby is so easy to monkey patch. It is very easy to modify a Ruby program without modifying a specific file.
|
93
|
-
Potentially undesirable to go down that path. Not sure. But, regardless, there are many ways to add
|
94
|
-
important code to a code base without disturbing certain files or at least minimally disturb them.
|
95
|
-
And, so, major improvements to code under the MPL can be made without technically triggering the copyleft
|
96
|
-
by leaving the old code in place and hooking new code into it.
|
97
|
-
* Makes it clear what license contributions are under (if using license headers in files.) This is because
|
98
|
-
1) modifications to existing files are MPL-2.0 via terms of the license, regardless of contributor intent.
|
99
|
-
2) new files can be force via the build to have license headers and therefore would express intent
|
100
|
-
by the contributor to license the code as MPL-2.0.
|
101
|
-
|
102
|
-
* Why irrelevant? Because github inbound=outbound convention means if the project is under X license
|
103
|
-
then a contribution is under X license by default.
|
104
|
-
* OSL-3.0
|
105
|
-
* Pros
|
106
|
-
* This was the license I liked best of all the licenses I read. It felt quite fair and robust.
|
107
|
-
* Cons
|
108
|
-
* incompatible with not only GPLv2 but all GPL. So it's really dead-on-arrival.
|
109
|
-
* Is not popular and hasn't been defended in court.
|
110
|
-
* EUPL and CDDL
|
111
|
-
* Based on MPL-1.1 and not compatible with GPLv2
|
112
|
-
* LGPL
|
113
|
-
* Not very concise especially for an interpreted language.
|
114
|
-
* I'm worried about users incorrectly lumping it in with strong copyleft.
|
115
|
-
* I find it interesting that GNU recommends that you don't use LGPL.
|
116
|
-
* I think the philosophical/political views of the license authors on OSS are not really necessary
|
117
|
-
and I'm hesitant to make it seem like it's a position communicated by a community.
|
118
|
-
|
119
|
-
### Other concern about the murky state of generative AI and copyright implications
|
120
|
-
|
121
|
-
I would like similar code generated from AI trained on code from this project, or prompted with code
|
122
|
-
from this project, to be considered a derived work.
|
123
|
-
|
124
|
-
It doesn't seem like any of the existing popular licenses influence whether or not an AI-generated work
|
125
|
-
is considered derived or not.
|
126
|
-
|
127
|
-
# [RETRACTED] 2024-05-19 License under user choice of 3 licenses
|
128
|
-
|
129
|
-
## Decision
|
130
|
-
|
131
|
-
RETRACTED: kept in the history but should relocate these thoughts to some other resource.
|
132
|
-
|
133
|
-
Release foobara gem (this repository) under the user's preference of
|
134
|
-
3 different licenses: `MIT OR Apache 2.0 OR MPL 2.0` and come up with a shorter alias for this license.
|
135
|
-
|
136
|
-
## Rationale
|
137
|
-
|
138
|
-
### Why MIT OR Apache 2.0
|
139
|
-
|
140
|
-
#### Why MIT is attractive
|
141
|
-
|
142
|
-
MIT is attractive, aside from the obvious (permissible, simple), because this license
|
143
|
-
is the typical license used in the Ruby community. Adoption would be as known-to-be-simple as possible under
|
144
|
-
this license in this ecosystem.
|
145
|
-
|
146
|
-
#### Why Apache 2.0 is attractive
|
147
|
-
|
148
|
-
Apache 2.0 is attractive due to its robustness and extending patent permissions to users.
|
149
|
-
|
150
|
-
#### Why MIT OR Apache 2.0 is attractive
|
151
|
-
|
152
|
-
Dual-licensing under both allows the end-user to operate under either as-needed.
|
153
|
-
|
154
|
-
The Rust community dual licenses under these two suggesting that a community can function under such
|
155
|
-
a licensing scheme.
|
156
|
-
|
157
|
-
Also, Bootstrap, in 2012, relicensed from Apache 2.0 to MIT so that GPLv2 projects could use Bootstrap.
|
158
|
-
Dual licensing would have also been a solution but the point here is future-proofing unexpected pressure to
|
159
|
-
relicense for adoption-sake.
|
160
|
-
|
161
|
-
### Why OR MPL 2.0
|
162
|
-
|
163
|
-
#### why MPL 2.0 is attractive
|
164
|
-
|
165
|
-
MPL 2.0 seems to me (I am not an expert on this and far from it) after some research to be a robust license
|
166
|
-
that seems to give nearly as much encouragement to give contributors back improvements to their
|
167
|
-
original efforts without sacrificing much, if any, practical permissiveness.
|
168
|
-
|
169
|
-
#### Why OR MPL 2.0, ie, why is MPL 2.0 scary
|
170
|
-
|
171
|
-
It seems like there would be no serious practical burden imposed on users by the MPL 2.0 license. But I'm not
|
172
|
-
100% certain of that without expert confirmation. And so, if users are also uncertain, that might hurt adoption
|
173
|
-
even if in actuality the license is not a hassle to users in any meaningful way.
|
174
|
-
|
175
|
-
What I mean by this is: if I have an MIT-licensed project, or a proprietary project, and I add a MPL-2.0 only gem
|
176
|
-
to my .gemspec, is there any administrative burden imposed? It seems like "no" but again I am not an expert.
|
177
|
-
If the answer is "no" but unclear to the user, that might still hurt adoption. To that extent, if confused with GPL
|
178
|
-
style licenses, it might be ruled out by some organizations even if incorrectly so.
|
179
|
-
|
180
|
-
However, making it OR MIT OR Apache 2.0 allows the user to just operate as if the project were licensed in
|
181
|
-
the way most convenient to the user among those options, making adoption, I assume, at least as easy as MIT alone.
|
182
|
-
|
183
|
-
But the real suspected benefit is this seems like it would allow MPL 2.0 to be the preferred license in the future
|
184
|
-
without needing to seek relicense permission from contributors, nor CLAs to avoid seeking relicense permission.
|
185
|
-
It is, in essence, a solution to punt and get back to coding for now and revisit with more real-world information
|
186
|
-
later.
|
187
|
-
|
188
|
-
### What would have been an ideal license?
|
189
|
-
|
190
|
-
Hard to say without being an expert on licenses and user behavior but, at this time, my best (admittedly uninformed)
|
191
|
-
guess would be to ideally use only one license, similar to MPL 2.0, but:
|
192
|
-
|
193
|
-
1) without the file-level/static stuff as it is likely irrelevant for a gem like Foobara.
|
194
|
-
2) with a network-exposure-is-distribution clause like AGPL 3.0, or really anything to maximize an
|
195
|
-
"if you improve it and make use of those improvements, then share the improvements" vibe, which,
|
196
|
-
with github and forks, seems like a trivial requirement to satisfy.
|
197
|
-
3) if possible, a clause stating that code generated from Foobara code as
|
198
|
-
training data or prompt data to an AI system constitutes a derived work.
|
199
|
-
|
200
|
-
Without expertise and given the point in history where I'm making this decision, I can't really draft
|
201
|
-
such a license and even if I could that seems like it could be a bad strategy regardless (aka license proliferation)
|
202
|
-
|
203
|
-
NOTE: if you happen to know an easy way for me to access expertise for clarity on these issues, please let me know.
|
204
|
-
I'd be happy to pay for a short consult with a professional (ie lawyer who specializes in open-source licensing.)
|
205
|
-
|
206
|
-
## Conclusion
|
207
|
-
|
208
|
-
License under MIT OR Apache 2.0 OR MPL 2.0 for now to:
|
209
|
-
|
210
|
-
1) guarantee seamless fit into Ruby ecosystem (MIT)
|
211
|
-
2) extend patent-granting in case somebody wants that (Apache 2.0/MPL 2.0)
|
212
|
-
3) allow future relicensing under MPL 2.0 without CLAs or non-trivial-contributor-roundup if it turns out that MPL 2.0
|
213
|
-
would have been a good choice once more is understood about the adoption-impact of having chosen that license.
|
214
|
-
4) stop thinking about licensing and get back to hackin'
|
215
|
-
|
216
|
-
To be clear, we are punting for now. At some point, we should choose either:
|
217
|
-
|
218
|
-
1) MPL 2.0
|
219
|
-
2) MIT OR Apache 2.0 (works for Rust community... seems there's no need to decide between these two)
|
220
|
-
3) Some other better-fitting license (would require permission from non-trivial contributors)
|
data/Guardfile
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
guard :rspec, all_after_pass: true, all_on_start: true, cmd: "bundle exec rspec", failed_mode: :focus do
|
2
|
-
watch(%r{^spec/(.+)_spec\.rb$})
|
3
|
-
watch(%r{^src/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
4
|
-
watch(%r{^src/foobara/command/concerns/(.+)\.rb$}) { |_m| "spec/foobara/command_spec.rb" }
|
5
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
6
|
-
watch(%r{^spec/spec_helper.rb$}) { "spec/" }
|
7
|
-
watch(%r{^src/commands.rb$/}) { "spec/" }
|
8
|
-
watch(%r{^projects/([^/]+)/src/(.+)\.rb$}) { |m| "spec/foobara/#{m[1]}/#{m[2]}_spec.rb" }
|
9
|
-
end
|
data/Rakefile
DELETED
data/concepts.md
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
<!-- TOC -->
|
2
|
-
|
3
|
-
* [Command](#command)
|
4
|
-
* [Type < Value::Processor](#type--valueprocessor)
|
5
|
-
* [type declaration value](#type-declaration-value)
|
6
|
-
* [Type reference](#type-reference)
|
7
|
-
* [Domain](#domain)
|
8
|
-
* [Organization](#organization)
|
9
|
-
* [Domain mapper](#domain-mapper)
|
10
|
-
* [Value::Processor](#valueprocessor)
|
11
|
-
* [Value::Caster < Value::Processor](#valuecaster--valueprocessor)
|
12
|
-
* [Value::Validator < Value::Processor](#valuevalidator--valueprocessor)
|
13
|
-
* [Value::Transformer < Value::Processor](#valuetransformer--valueprocessor)
|
14
|
-
* [Desugarizer < Value::Transformer](#desugarizer--valuetransformer)
|
15
|
-
* [TypeDeclarationValidator < Value::Validator](#typedeclarationvalidator--valuevalidator)
|
16
|
-
* [in general:](#in-general)
|
17
|
-
* [types and type declarations:](#types-and-type-declarations)
|
18
|
-
|
19
|
-
<!-- TOC -->
|
20
|
-
|
21
|
-
These are notes about some things conceptual.
|
22
|
-
|
23
|
-
# Command
|
24
|
-
|
25
|
-
* A command is an encapsulation of a high-level business operation and is intended to be the public
|
26
|
-
interface of a system or subsystem.
|
27
|
-
|
28
|
-
# Type < Value::Processor
|
29
|
-
|
30
|
-
A type is an instance of the Types::Type class.
|
31
|
-
|
32
|
-
It (the instance) is a namespace.
|
33
|
-
|
34
|
-
It is a Value::Processor
|
35
|
-
|
36
|
-
* reflection
|
37
|
-
* can give a type declaration value (formal or informal/sugary or strict) for this type
|
38
|
-
* can give the list of possible errors that could result from processing a value of this type
|
39
|
-
and the types for their context schemas
|
40
|
-
* can answer what value processors are supported for values of this type
|
41
|
-
* can answer which value processors are automatically applied for values of this type
|
42
|
-
* can serve as a base type for another type
|
43
|
-
* can process a value of this type
|
44
|
-
* can answer if a value needs to be cast
|
45
|
-
* can answer if a value can be cast
|
46
|
-
* can cast a value into an value of this type
|
47
|
-
* can transform a value of this type
|
48
|
-
* can validate a value of this type
|
49
|
-
* processor registry operations
|
50
|
-
* can register a supported value processor
|
51
|
-
* can register a value caster
|
52
|
-
|
53
|
-
# type declaration value
|
54
|
-
|
55
|
-
* Something that defines/declares a type in a declarative fashion.
|
56
|
-
* Can have a sugary form for human expression/readability/writability
|
57
|
-
* Is easily serializable for cross-system metaprogramming
|
58
|
-
* example:
|
59
|
-
```ruby
|
60
|
-
{
|
61
|
-
foo: :integer,
|
62
|
-
bar: [:integer, :optional, :allow_blank, min: 1]
|
63
|
-
}
|
64
|
-
```
|
65
|
-
* In this example, we are using a sugary declaration to specify a new type of
|
66
|
-
attributes type that can represent a value like `{ foo: -20, bar: 10 }`
|
67
|
-
|
68
|
-
# Type reference
|
69
|
-
|
70
|
-
* References a "registered" type. A registered type has a type symbol and belongs to a domain.
|
71
|
-
* An unresolved type reference doesn't have to be absolute and is looked up in the current
|
72
|
-
Foobara namespace.
|
73
|
-
* A resolved type is absolute.
|
74
|
-
* A type reference can be used as a type declaration.
|
75
|
-
|
76
|
-
# Domain
|
77
|
-
|
78
|
-
* A namespace for Commands and Types
|
79
|
-
* can depend on other domains in a unidirectional way
|
80
|
-
|
81
|
-
# Organization
|
82
|
-
|
83
|
-
* namespace for collecting domains
|
84
|
-
|
85
|
-
# Domain mapper
|
86
|
-
|
87
|
-
* Translates models (or types or commands inputs/results) to models (or types or command inputs/results) in
|
88
|
-
another domain.
|
89
|
-
|
90
|
-
# Value::Processor
|
91
|
-
|
92
|
-
* Has a process_value method that receives a value and returns an Outcome
|
93
|
-
* Can have an applicable?(value) method
|
94
|
-
* Answers what errors are possible
|
95
|
-
* Including the type of their context
|
96
|
-
|
97
|
-
## Value::Caster < Value::Processor
|
98
|
-
|
99
|
-
* gives #cast instead of #transform but same idea, takes value returns value
|
100
|
-
* like ValueProcessor, never gives errors
|
101
|
-
* only one value caster per type should be #applicable? for a given value.
|
102
|
-
* Therefore doesn't have to play nicely with other Casters, unlike Transformers/Validators
|
103
|
-
|
104
|
-
## Value::Validator < Value::Processor
|
105
|
-
|
106
|
-
* gives #validation_errors that takes value and returns errors
|
107
|
-
* never gives new value
|
108
|
-
|
109
|
-
## Value::Transformer < Value::Processor
|
110
|
-
|
111
|
-
* gives #transfomer that takes value and returns value
|
112
|
-
* never gives errors
|
113
|
-
|
114
|
-
## Desugarizer < Value::Transformer
|
115
|
-
|
116
|
-
* takes sugary type declaration and returns strict type declaration
|
117
|
-
|
118
|
-
## TypeDeclarationValidator < Value::Validator
|
119
|
-
|
120
|
-
* Validates type declarations
|
121
|
-
|
122
|
-
A way to think about the interfaces/concepts involved here, if helpful:
|
123
|
-
|
124
|
-
### in general:
|
125
|
-
|
126
|
-
* Processor, Multi, Selection, Pipeline: value -> outcome
|
127
|
-
* Multi < Processor: value -> outcome
|
128
|
-
* Selection < Multi (chooses 1 processor among many to run): value -> outcome
|
129
|
-
* Pipeline < Multi (chains a collection of processors together): value -> outcome
|
130
|
-
* Processor, Multi, Selection, Pipeline: value -> outcome
|
131
|
-
* Transformer: value -> value
|
132
|
-
* Validator: value -> error[]
|
133
|
-
|
134
|
-
Maybe not helpful, but, you could think of Processor/Multi/Selection/Pipeline as monads
|
135
|
-
and Validator and Transformer as monads but with convenience methods that make assumptions
|
136
|
-
about the context (transformer assumes there are no errors and validator assumes
|
137
|
-
no transformation of the value.)
|
138
|
-
|
139
|
-
### types and type declarations:
|
140
|
-
|
141
|
-
* TypeDeclarationHandler: type declaration -> Type instance
|
142
|
-
* TypeDeclarationHandlerRegistry: type declaration -> outcome<TypeDeclarationHandler>
|
143
|
-
* Desugarizer: type declaration -> strict(er) type declaration
|
144
|
-
* TypeDeclarationValidator: strict type declaration -> error[]
|
145
|
-
* Type instance: value -> outcome
|
146
|
-
* Type casting (is a Value::Pipeline of casters): value -> value
|
147
|
-
* Caster: value -> value
|
148
|
-
* Type transformers: value -> value
|
149
|
-
* Type validators: value -> error[]
|
150
|
-
* Type processors: value -> outcome
|
151
|
-
* Supported type processors: value -> outcome
|
152
|
-
* Supported type transformers: value -> value
|
153
|
-
* Supported type validators: value -> error[]
|