paper_trail-human 0.4.0 → 0.5.0

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: 4dea24fd23784bda5b3b0f6d704f5f3a53a2ab00c8ed8500fe69a1b432eb3f47
4
- data.tar.gz: 6c074d6f13efd43f93e1c201e36d9310420095c516980bc80c74dc6116551105
3
+ metadata.gz: dfb8c783e819dfade94289a84366e1d04f13f711339c6c08ca471d4a2daac52c
4
+ data.tar.gz: 6ff6a8161a65ee10cc25a84c77f5986a33c9a13b285854efc7e8fce30597f198
5
5
  SHA512:
6
- metadata.gz: bf9745f8aba245105b94e41f5739ec4358d657311d7cc9b5527db3353ff1e217243955f3f033cd576f98fd0d8fa0a6079f927496f101a4be31813bc734ac75bd
7
- data.tar.gz: e5fb5fc24f36be842103d727af163f64545c0208229178dd7bc93f2559b09022d5177cffb4c82e448aed78a21a5564a6ff79376875184c9501b298685ff37e37
6
+ metadata.gz: dcc23c680e095752b9413ece751ebb82c5d4b3b8bf060811d01acfb775f4b803f2a65a318f175d40e288716b2bf6a13e35ca56a586391187900d60a1f2b0ec5c
7
+ data.tar.gz: '08542e032fd13d2e8ad3a9ae4949145ca5bf82d0e5290cbc2387393df0cbf1de8ebb4724fb16ea756b96394a5a43e4add686f4f9b14612f9cd7c85b78e0fe22c'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0] - 2026-06-01
4
+
5
+ ### Added
6
+ - Text diff mode: `m.field :body, :text, diff: true` returns additions/deletions/summary
7
+ - Event system: `config.on_format { |result, version| ... }` for multiple callbacks
8
+ - Callbacks are fault-tolerant (errors in one don't block others)
9
+ - `resolve_pair?` port method for resolvers that need both old and new values
10
+
11
+ ### Changed
12
+ - Extracted `AfterFormat` module shared by `Presenter` and `BatchPresenter`
13
+
3
14
  ## [0.4.0] - 2026-05-31
4
15
 
5
16
  ### Added
@@ -9,13 +9,39 @@ module PaperTrail
9
9
 
10
10
  DEFAULT_MAX_LENGTH = 80
11
11
 
12
- def initialize(max_length: DEFAULT_MAX_LENGTH, show_diff_stats: false, **)
12
+ def initialize(max_length: DEFAULT_MAX_LENGTH, show_diff_stats: false, diff: false, **)
13
13
  @max_length = max_length
14
14
  @show_diff_stats = show_diff_stats
15
+ @diff = diff
16
+ end
17
+
18
+ def resolve_pair?
19
+ @diff
15
20
  end
16
21
 
17
22
  def resolve(value)
18
- text = value.to_s
23
+ truncate(value.to_s)
24
+ end
25
+
26
+ def resolve_change(previous_value, new_value)
27
+ old_lines = previous_value.to_s.lines.map(&:chomp)
28
+ new_lines = new_value.to_s.lines.map(&:chomp)
29
+
30
+ additions = (new_lines - old_lines).size
31
+ deletions = (old_lines - new_lines).size
32
+
33
+ {
34
+ previous_value: truncate(previous_value.to_s),
35
+ value: truncate(new_value.to_s),
36
+ additions: additions,
37
+ deletions: deletions,
38
+ summary: "+#{additions}/-#{deletions} lines"
39
+ }
40
+ end
41
+
42
+ private
43
+
44
+ def truncate(text)
19
45
  return text if text.length <= @max_length
20
46
 
21
47
  truncated = "#{text[0, @max_length]}..."
@@ -7,7 +7,7 @@ module PaperTrail
7
7
 
8
8
  attr_accessor :whodunnit_resolver, :extend_version_model, :field_name_resolver,
9
9
  :translate_events, :after_format
10
- attr_reader :ignored_fields, :custom_resolvers, :custom_formatters
10
+ attr_reader :ignored_fields, :custom_resolvers, :custom_formatters, :format_callbacks
11
11
 
12
12
  def initialize
13
13
  @model_configs = {}
@@ -19,6 +19,7 @@ module PaperTrail
19
19
  @after_format = nil
20
20
  @custom_resolvers = {}
21
21
  @custom_formatters = {}
22
+ @format_callbacks = []
22
23
  @mutex = Mutex.new
23
24
  end
24
25
 
@@ -40,6 +41,10 @@ module PaperTrail
40
41
  @mutex.synchronize { @custom_formatters[type.to_sym] = klass }
41
42
  end
42
43
 
44
+ def on_format(&block)
45
+ @mutex.synchronize { @format_callbacks << block }
46
+ end
47
+
43
48
  def config_for(model_name)
44
49
  @model_configs[model_name.to_s]
45
50
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ module Human
5
+ module Core
6
+ module AfterFormat
7
+ private
8
+
9
+ def apply_after_format(result, version)
10
+ result = @configuration.after_format.call(result, version) if @configuration.after_format
11
+ @configuration.format_callbacks.each do |callback|
12
+ callback.call(result, version)
13
+ rescue StandardError
14
+ nil
15
+ end
16
+ result
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -4,6 +4,8 @@ module PaperTrail
4
4
  module Human
5
5
  module Core
6
6
  class BatchPresenter
7
+ include AfterFormat
8
+
7
9
  def initialize(configuration)
8
10
  @configuration = configuration
9
11
  @change_extractor = ChangeExtractor.new
@@ -122,12 +124,6 @@ module PaperTrail
122
124
  rescue NameError
123
125
  {}
124
126
  end
125
-
126
- def apply_after_format(result, version)
127
- return result unless @configuration.after_format
128
-
129
- @configuration.after_format.call(result, version)
130
- end
131
127
  end
132
128
  end
133
129
  end
@@ -26,11 +26,15 @@ module PaperTrail
26
26
  config = field_config(field_name)
27
27
  resolver = build_resolver(config, field_name)
28
28
 
29
- {
30
- field: human_field_name(field_name),
31
- previous_value: resolve_value(resolver, previous_value),
32
- value: resolve_value(resolver, new_value)
33
- }
29
+ if resolver&.resolve_pair?
30
+ resolver.resolve_change(previous_value, new_value).merge(field: human_field_name(field_name))
31
+ else
32
+ {
33
+ field: human_field_name(field_name),
34
+ previous_value: resolve_value(resolver, previous_value),
35
+ value: resolve_value(resolver, new_value)
36
+ }
37
+ end
34
38
  end
35
39
 
36
40
  private
@@ -4,6 +4,8 @@ module PaperTrail
4
4
  module Human
5
5
  module Core
6
6
  class Presenter
7
+ include AfterFormat
8
+
7
9
  def initialize(configuration)
8
10
  @configuration = configuration
9
11
  @change_extractor = ChangeExtractor.new
@@ -68,12 +70,6 @@ module PaperTrail
68
70
 
69
71
  result
70
72
  end
71
-
72
- def apply_after_format(result, version)
73
- return result unless @configuration.after_format
74
-
75
- @configuration.after_format.call(result, version)
76
- end
77
73
  end
78
74
  end
79
75
  end
@@ -7,6 +7,10 @@ module PaperTrail
7
7
  def resolve(value)
8
8
  raise NotImplementedError, "#{self.class}#resolve must be implemented"
9
9
  end
10
+
11
+ def resolve_pair?
12
+ false
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module PaperTrail
4
4
  module Human
5
- VERSION = '0.4.0'
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
@@ -5,6 +5,7 @@ require_relative 'human/configuration'
5
5
  require_relative 'human/core/change_extractor'
6
6
  require_relative 'human/core/field_formatter'
7
7
  require_relative 'human/core/event_translator'
8
+ require_relative 'human/core/after_format'
8
9
  require_relative 'human/core/presenter'
9
10
  require_relative 'human/core/batch_presenter'
10
11
  require_relative 'human/core/timeline'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paper_trail-human
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel
@@ -65,6 +65,7 @@ files:
65
65
  - lib/paper_trail/human/adapters/resolvers/relation.rb
66
66
  - lib/paper_trail/human/adapters/resolvers/text.rb
67
67
  - lib/paper_trail/human/configuration.rb
68
+ - lib/paper_trail/human/core/after_format.rb
68
69
  - lib/paper_trail/human/core/batch_presenter.rb
69
70
  - lib/paper_trail/human/core/change_extractor.rb
70
71
  - lib/paper_trail/human/core/event_translator.rb