milestoner 16.2.1 → 17.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -1
  3. data/README.adoc +274 -47
  4. data/lib/milestoner/builders/container.rb +15 -0
  5. data/lib/milestoner/builders/import.rb +9 -0
  6. data/lib/milestoner/builders/stream.rb +29 -0
  7. data/lib/milestoner/builders/web.rb +41 -0
  8. data/lib/milestoner/cli/actions/build/format.rb +24 -0
  9. data/lib/milestoner/cli/actions/build/label.rb +26 -0
  10. data/lib/milestoner/cli/actions/build/layout.rb +36 -0
  11. data/lib/milestoner/cli/actions/build/root.rb +25 -0
  12. data/lib/milestoner/cli/actions/build/version.rb +31 -0
  13. data/lib/milestoner/cli/actions/cache/create.rb +35 -0
  14. data/lib/milestoner/cli/actions/cache/delete.rb +34 -0
  15. data/lib/milestoner/cli/actions/cache/find.rb +34 -0
  16. data/lib/milestoner/cli/actions/cache/info.rb +29 -0
  17. data/lib/milestoner/cli/actions/cache/list.rb +33 -0
  18. data/lib/milestoner/cli/actions/publish.rb +9 -5
  19. data/lib/milestoner/cli/commands/build.rb +55 -0
  20. data/lib/milestoner/cli/commands/cache.rb +27 -0
  21. data/lib/milestoner/cli/shell.rb +3 -2
  22. data/lib/milestoner/commits/categorizer.rb +21 -29
  23. data/lib/milestoner/commits/collector.rb +18 -0
  24. data/lib/milestoner/commits/enricher.rb +52 -0
  25. data/lib/milestoner/commits/enrichers/author.rb +26 -0
  26. data/lib/milestoner/commits/enrichers/body.rb +28 -0
  27. data/lib/milestoner/commits/enrichers/colleague.rb +33 -0
  28. data/lib/milestoner/commits/enrichers/container.rb +25 -0
  29. data/lib/milestoner/commits/enrichers/format.rb +23 -0
  30. data/lib/milestoner/commits/enrichers/import.rb +11 -0
  31. data/lib/milestoner/commits/enrichers/issue.rb +28 -0
  32. data/lib/milestoner/commits/enrichers/milestone.rb +24 -0
  33. data/lib/milestoner/commits/enrichers/note.rb +28 -0
  34. data/lib/milestoner/commits/enrichers/review.rb +23 -0
  35. data/lib/milestoner/commits/enrichers/uri.rb +14 -0
  36. data/lib/milestoner/commits/versioner.rb +48 -0
  37. data/lib/milestoner/configuration/contract.rb +29 -3
  38. data/lib/milestoner/configuration/defaults.yml +31 -8
  39. data/lib/milestoner/configuration/model.rb +24 -1
  40. data/lib/milestoner/configuration/transformers/build/root.rb +21 -0
  41. data/lib/milestoner/configuration/transformers/build/template_paths.rb +35 -0
  42. data/lib/milestoner/configuration/transformers/citations/description.rb +37 -0
  43. data/lib/milestoner/configuration/transformers/citations/label.rb +37 -0
  44. data/lib/milestoner/configuration/transformers/gems/description.rb +36 -0
  45. data/lib/milestoner/configuration/transformers/gems/label.rb +36 -0
  46. data/lib/milestoner/configuration/transformers/gems/name.rb +36 -0
  47. data/lib/milestoner/configuration/transformers/gems/uri.rb +36 -0
  48. data/lib/milestoner/configuration/transformers/project/author.rb +33 -0
  49. data/lib/milestoner/configuration/transformers/project/generator.rb +28 -0
  50. data/lib/milestoner/configuration/transformers/project/label.rb +23 -0
  51. data/lib/milestoner/configuration/transformers/project/name.rb +19 -0
  52. data/lib/milestoner/configuration/transformers/project/version.rb +31 -0
  53. data/lib/milestoner/configuration/transformers/uri/avatar.rb +21 -0
  54. data/lib/milestoner/configuration/transformers/uri/commit.rb +24 -0
  55. data/lib/milestoner/configuration/transformers/uri/profile.rb +21 -0
  56. data/lib/milestoner/configuration/transformers/uri/review.rb +24 -0
  57. data/lib/milestoner/configuration/transformers/uri/tracker.rb +24 -0
  58. data/lib/milestoner/container.rb +51 -9
  59. data/lib/milestoner/models/commit.rb +42 -0
  60. data/lib/milestoner/models/link.rb +12 -0
  61. data/lib/milestoner/models/user.rb +12 -0
  62. data/lib/milestoner/renderers/asciidoc.rb +20 -0
  63. data/lib/milestoner/renderers/markdown.rb +20 -0
  64. data/lib/milestoner/renderers/universal.rb +26 -0
  65. data/lib/milestoner/tags/creator.rb +31 -23
  66. data/lib/milestoner/tags/publisher.rb +5 -5
  67. data/lib/milestoner/tags/pusher.rb +9 -3
  68. data/lib/milestoner/templates/layouts/page.html.erb +29 -0
  69. data/lib/milestoner/templates/layouts/page.stream.erb +1 -0
  70. data/lib/milestoner/templates/milestones/_avatar.html.erb +5 -0
  71. data/lib/milestoner/templates/milestones/_commit.html.erb +104 -0
  72. data/lib/milestoner/templates/milestones/_commit.stream.erb +1 -0
  73. data/lib/milestoner/templates/milestones/_icon.html.erb +6 -0
  74. data/lib/milestoner/templates/milestones/_profile.html.erb +5 -0
  75. data/lib/milestoner/templates/milestones/show.html.erb +46 -0
  76. data/lib/milestoner/templates/milestones/show.stream.erb +5 -0
  77. data/lib/milestoner/templates/public/page.css.erb +356 -0
  78. data/lib/milestoner/views/context.rb +25 -0
  79. data/lib/milestoner/views/milestones/show.rb +46 -0
  80. data/lib/milestoner/views/parts/commit.rb +85 -0
  81. data/lib/milestoner.rb +1 -1
  82. data/milestoner.gemspec +17 -11
  83. data.tar.gz.sig +0 -0
  84. metadata +172 -26
  85. metadata.gz.sig +0 -0
  86. data/lib/milestoner/cli/actions/status.rb +0 -37
  87. data/lib/milestoner/presenters/commit.rb +0 -36
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit URI based on trailer information.
7
+ class URI
8
+ include Milestoner::Import[:input]
9
+
10
+ def call(commit) = format input.commit_uri, id: commit.sha
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "versionaire"
5
+
6
+ module Milestoner
7
+ module Commits
8
+ # Calculates next version based on commit trailer version keys.
9
+ class Versioner
10
+ include Import[:git]
11
+ include Dry::Monads[:result]
12
+
13
+ using Versionaire::Cast
14
+
15
+ DEFAULTS = {trailer_key: "Milestone", fallback: Versionaire::Version.new}.freeze
16
+
17
+ def initialize(defaults: DEFAULTS, collector: Collector.new, **)
18
+ @defaults = defaults
19
+ @collector = collector
20
+ super(**)
21
+ end
22
+
23
+ def call
24
+ trailer_milestones.then { |milestones| bump milestones }
25
+ .value_or(fallback)
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :defaults, :collector
31
+
32
+ def trailer_milestones
33
+ collector.call.value_or([]).each.with_object [] do |commit, values|
34
+ commit.trailer_value_for(trailer_key).bind { |milestone| values.append milestone.to_sym }
35
+ end
36
+ end
37
+
38
+ def bump milestones
39
+ target = fallback.members.intersection(milestones).first
40
+ git.tag_last.fmap { |tag| target ? Version(tag).bump(target) : fallback }
41
+ end
42
+
43
+ def trailer_key = defaults.fetch __method__
44
+
45
+ def fallback = defaults.fetch __method__
46
+ end
47
+ end
48
+ end
@@ -8,9 +8,35 @@ Dry::Schema.load_extensions :monads
8
8
  module Milestoner
9
9
  module Configuration
10
10
  Contract = Dry::Schema.Params do
11
- required(:documentation_format).filled :string
12
- required(:prefixes).array :string
13
- optional(:version).filled :string
11
+ required(:avatar_domain).filled :string
12
+ required(:avatar_uri).filled :string
13
+ required(:build_format).filled :string
14
+ required(:build_layout) { str? | bool? }
15
+ required(:build_root).filled Etcher::Types::Pathname
16
+ required(:build_template_paths).array Etcher::Types::Pathname
17
+
18
+ required(:commit_categories).array(:hash) do
19
+ required(:emoji).filled :string
20
+ required(:label).filled :string
21
+ end
22
+
23
+ required(:commit_domain).filled :string
24
+ required(:commit_format).filled :string
25
+ required(:commit_uri).filled :string
26
+ required(:profile_domain).filled :string
27
+ required(:profile_uri).filled :string
28
+ required(:project_author).filled :string
29
+ optional(:project_description).filled :string
30
+ required(:project_generator).filled :string
31
+ optional(:project_label).filled :string
32
+ required(:project_name).filled :string
33
+ optional(:project_owner).filled :string
34
+ optional(:project_uri).filled :string
35
+ required(:project_version).filled Etcher::Types::Version
36
+ required(:review_domain).filled :string
37
+ required(:review_uri).filled :string
38
+ required(:tracker_domain).filled :string
39
+ required(:tracker_uri).filled :string
14
40
  end
15
41
  end
16
42
  end
@@ -1,8 +1,31 @@
1
- documentation:
2
- format: "adoc"
3
- prefixes:
4
- - Fixed
5
- - Added
6
- - Updated
7
- - Removed
8
- - Refactored
1
+ avatar:
2
+ domain: https://avatars.githubusercontent.com
3
+ uri: "%<domain>s/u/%<id>s"
4
+ build:
5
+ format: web
6
+ layout: page
7
+ root: tmp/milestone
8
+ commit:
9
+ categories:
10
+ - emoji: ✅
11
+ label: Fixed
12
+ - emoji: 🟢
13
+ label: Added
14
+ - emoji: 🔼
15
+ label: Updated
16
+ - emoji: ⛔️
17
+ label: Removed
18
+ - emoji: 🔁
19
+ label: Refactored
20
+ domain: https://github.com
21
+ format: asciidoc
22
+ uri: "%<domain>s/%<owner>s/%<name>s/commit/%<id>s"
23
+ profile:
24
+ domain: https://github.com
25
+ uri: "%<domain>s/%<id>s"
26
+ review:
27
+ domain: https://github.com
28
+ uri: "%<domain>s/%<owner>s/%<name>s/pulls/%<id>s"
29
+ tracker:
30
+ domain: https://github.com
31
+ uri: "%<domain>s/%<owner>s/%<name>s/issues/%<id>s"
@@ -3,6 +3,29 @@
3
3
  module Milestoner
4
4
  module Configuration
5
5
  # Defines configuration content as the primary source of truth for use throughout the gem.
6
- Model = Struct.new :documentation_format, :prefixes, :version
6
+ Model = Struct.new :avatar_domain,
7
+ :avatar_uri,
8
+ :build_format,
9
+ :build_layout,
10
+ :build_root,
11
+ :build_template_paths,
12
+ :commit_categories,
13
+ :commit_domain,
14
+ :commit_format,
15
+ :commit_uri,
16
+ :profile_domain,
17
+ :profile_uri,
18
+ :project_author,
19
+ :project_description,
20
+ :project_generator,
21
+ :project_label,
22
+ :project_name,
23
+ :project_owner,
24
+ :project_uri,
25
+ :project_version,
26
+ :review_domain,
27
+ :review_uri,
28
+ :tracker_domain,
29
+ :tracker_uri
7
30
  end
8
31
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "refinements/hash"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ # Ensures build root is expanded.
11
+ module Build
12
+ using Refinements::Hash
13
+
14
+ Root = lambda do |content, key = :build_root|
15
+ content.transform_with! key => -> value { Pathname(value).expand_path }
16
+ Dry::Monads::Success content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "runcom"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Build
11
+ # Ensures XDG configuration and gem template paths are configured.
12
+ class TemplatePaths
13
+ include Dry::Monads[:result]
14
+
15
+ def initialize key = :build_template_paths,
16
+ default: Pathname(__dir__).join("../../../templates"),
17
+ xdg_config: Runcom::Config.new("milestoner/templates")
18
+ @key = key
19
+ @default = default
20
+ @xdg_config = xdg_config
21
+ end
22
+
23
+ def call content
24
+ content[key] = xdg_config.all.append default
25
+ Success content
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :key, :default, :xdg_config
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cff"
4
+ require "dry/monads"
5
+ require "pathname"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Citations
11
+ # Conditionally updates project description based on citation details.
12
+ class Description
13
+ include Dry::Monads[:result]
14
+
15
+ def initialize key = :project_description,
16
+ path: Pathname.pwd.join("CITATION.cff"),
17
+ citation: CFF::File
18
+ @key = key
19
+ @path = path
20
+ @citation = citation
21
+ end
22
+
23
+ def call(content) = Success process(content)
24
+
25
+ private
26
+
27
+ attr_reader :key, :path, :citation
28
+
29
+ def process content
30
+ content.fetch(key) { citation.open(path).abstract }
31
+ .then { |value| String(value).empty? ? content : content.merge!(key => value) }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cff"
4
+ require "dry/monads"
5
+ require "pathname"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Citations
11
+ # Conditionally updates project label based on citation details.
12
+ class Label
13
+ include Dry::Monads[:result]
14
+
15
+ def initialize key = :project_label,
16
+ path: Pathname.pwd.join("CITATION.cff"),
17
+ citation: CFF::File
18
+ @key = key
19
+ @path = path
20
+ @citation = citation
21
+ end
22
+
23
+ def call(content) = Success process(content)
24
+
25
+ private
26
+
27
+ attr_reader :key, :path, :citation
28
+
29
+ def process content
30
+ content.fetch(key) { citation.open(path).title }
31
+ .then { |value| String(value).empty? ? content : content.merge!(key => value) }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project description based on specification summary.
12
+ class Description
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_description, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call(content) = Success process(content)
23
+
24
+ private
25
+
26
+ attr_reader :key, :path
27
+
28
+ def process content
29
+ content.fetch(key) { spec_loader.call(path).summary }
30
+ .then { |value| String(value).empty? ? content : content.merge!(key => value) }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project label based on specification label.
12
+ class Label
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_label, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call(content) = Success process(content)
23
+
24
+ private
25
+
26
+ attr_reader :key, :path
27
+
28
+ def process content
29
+ content.fetch(key) { spec_loader.call(path).label }
30
+ .then { |value| value == "Undefined" ? content : content.merge!(key => value) }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project name based on specification name.
12
+ class Name
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_name, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call(content) = Success process(content)
23
+
24
+ private
25
+
26
+ attr_reader :key, :path
27
+
28
+ def process content
29
+ content.fetch(key) { spec_loader.call(path).name }
30
+ .then { |value| String(value).empty? ? content : content.merge!(key => value) }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project URI based on specification home page URL.
12
+ class URI
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_uri, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call(content) = Success process(content)
23
+
24
+ private
25
+
26
+ attr_reader :key, :path
27
+
28
+ def process content
29
+ content.fetch(key) { spec_loader.call(path).homepage_url }
30
+ .then { |value| String(value).empty? ? content : content.merge!(key => value) }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Milestoner
6
+ module Configuration
7
+ module Transformers
8
+ module Project
9
+ # Conditionally updates author based on Git user.
10
+ class Author
11
+ include Import[:git]
12
+ include Dry::Monads[:result]
13
+
14
+ def initialize(key = :project_author, **)
15
+ @key = key
16
+ super(**)
17
+ end
18
+
19
+ def call content
20
+ content.fetch(key) { git.get("user.name", nil).value_or(nil) }
21
+ .tap { |value| content[key] = value if value }
22
+
23
+ Success content
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :key
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Milestoner
6
+ module Configuration
7
+ module Transformers
8
+ module Project
9
+ # Conditionally updates generator based on gem specification.
10
+ class Generator
11
+ include Import[:specification]
12
+ include Dry::Monads[:result]
13
+
14
+ def initialize(key = :project_generator, **)
15
+ @key = key
16
+ super(**)
17
+ end
18
+
19
+ def call(content) = Success({key => specification.labeled_version}.merge!(content))
20
+
21
+ private
22
+
23
+ attr_reader :key
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "refinements/string"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ # Conditionally updates label based on current directory.
11
+ module Project
12
+ using Refinements::String
13
+
14
+ Label = lambda do |content, key = :project_label, default: Pathname.pwd.basename.to_s|
15
+ content.fetch(key) { default }
16
+ .tap { |value| content[key] = value.titleize }
17
+
18
+ Dry::Monads::Success content
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module Project
10
+ Name = lambda do |content, key = :project_name, default: Pathname.pwd.basename.to_s|
11
+ content.fetch(key) { default }
12
+ .tap { |value| content[key] = value }
13
+
14
+ Dry::Monads::Success content
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Milestoner
6
+ module Configuration
7
+ module Transformers
8
+ module Project
9
+ # Conditionally updates version based on last Git tag.
10
+ class Version
11
+ include Dry::Monads[:result]
12
+
13
+ def initialize key = :project_version, versioner: Commits::Versioner.new
14
+ @key = key
15
+ @versioner = versioner
16
+ end
17
+
18
+ def call content
19
+ content.fetch(key) { versioner.call }
20
+ .then { |value| content.merge! key => value }
21
+ .then { |update| Success update }
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :key, :versioner
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Avatar = lambda do |content, key = :avatar_uri|
11
+ domain, uri = content.values_at :avatar_domain, key
12
+
13
+ return Dry::Monads::Success content unless uri
14
+
15
+ content[key] = format uri, domain:, id: "%<id>s"
16
+ Dry::Monads::Success content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Commit = lambda do |content, key = :commit_uri|
11
+ owner, name, domain, uri = content.values_at :project_owner,
12
+ :project_name,
13
+ :commit_domain,
14
+ key
15
+
16
+ return Dry::Monads::Success content unless uri
17
+
18
+ content[key] = format uri, domain:, owner:, name:, id: "%<id>s"
19
+ Dry::Monads::Success content
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Profile = lambda do |content, key = :profile_uri|
11
+ domain, uri = content.values_at :profile_domain, key
12
+
13
+ return Dry::Monads::Success content unless uri
14
+
15
+ content[key] = format uri, domain:, id: "%<id>s"
16
+ Dry::Monads::Success content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end