Class: Psych::Merge::Provider

Inherits:
Object
  • Object
show all
Defined in:
lib/psych/merge/provider.rb,
sig/psych/merge.rbs

Overview

Conservative source-preserving provider for top-level YAML mappings. rubocop:disable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/ParameterLists, Metrics/PerceivedComplexity -- provider validation, planning, rendering, and verification form one safety boundary

Defined Under Namespace

Classes: Decision, Document, Entry

Constant Summary collapse

DEFAULT_PROFILE =
:source_preserving
DIALECTS =
%i[yaml].freeze

Instance Method Summary collapse

Instance Method Details

#analyze(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


57
58
59
60
61
62
63
64
65
66
67
# File 'lib/psych/merge/provider.rb', line 57

def analyze(request)
  document = analyze_role(:source, request.fetch(:source))
  return invalid_document_failure(:analyze, request, [document]) unless document.issues.empty?

  result(
    :analyze,
    request,
    analysis: analysis_payload(document),
    verification: { source_parsed: true, structurally_unambiguous: true }
  )
end

#capabilitiesHash[Symbol, untyped]

Returns:

  • (Hash[Symbol, untyped])


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/psych/merge/provider.rb', line 38

def capabilities
  {
    operations: Ast::Merge::ProviderContract::OPERATIONS,
    dialects: DIALECTS,
    backends: %i[psych],
    profiles: [DEFAULT_PROFILE],
    role: :backend,
    source_preservation: %i[
      exact_source
      mapping_entry_fragments
      comment_ownership
      line_provenance
      reparse
      semantic_verification
      ast_attribute_verification
    ]
  }.freeze
end

#diff2(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/psych/merge/provider.rb', line 69

def diff2(request)
  before = analyze_role(:before, request.fetch(:before_source))
  after = analyze_role(:after, request.fetch(:after_source))
  unsafe = [before, after].reject { |document| document.issues.empty? }
  return invalid_document_failure(:diff2, request, unsafe) unless unsafe.empty?

  changes = mapping_changes(before, after)
  result(
    :diff2,
    request,
    diff: { before: analysis_payload(before), after: analysis_payload(after), changes: changes },
    changes: changes,
    verification: { before_parsed: true, after_parsed: true }
  )
end

#familyString

Returns:

  • (String)


36
# File 'lib/psych/merge/provider.rb', line 36

def family = 'yaml'

#merge2(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/psych/merge/provider.rb', line 85

def merge2(request)
  documents = {
    incoming: analyze_role(:incoming, request.fetch(:incoming_source)),
    current: analyze_role(:current, request.fetch(:current_source))
  }
  unsafe = documents.values.reject { |document| document.issues.empty? }
  return invalid_document_failure(:merge2, request, unsafe) unless unsafe.empty?

  additions = documents[:incoming].entries.reject { |entry| documents[:current].by_key.key?(entry.key) }
  render_documents = { ours: documents[:current], theirs: documents[:incoming] }
  fragments = [whole_source_fragment(:ours, documents[:current].source)]
  fragments.concat(additions.map { |entry| entry_fragment(:theirs, entry) })
  rendered = render_plan(request, separated_fragments(fragments, render_documents))
  expected = [
    *documents[:current].entries.map { |entry| selected_entry(entry, :current) },
    *additions.map { |entry| selected_entry(entry, :incoming) }
  ]
  verification = verify_composite(rendered.content, expected)
  return verification_failure(:merge2, request, rendered, [], verification) unless verification[:semantic_match]

  result(
    :merge2,
    request,
    output: rendered.content,
    changes: mapping_changes(documents[:current], analyze_role(:output, rendered.content)),
    render_report: render_report(rendered, :exact_mapping_entry_composite),
    verification: verification
  )
end

#merge3(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/psych/merge/provider.rb', line 115

def merge3(request)
  documents = %i[base ours theirs].to_h do |role|
    [role, analyze_role(role, request.fetch(:"#{role}_source"))]
  end
  exact_role = exact_revision_role(documents)
  return render_exact(request, documents, exact_role) if exact_role

  unsafe = documents.values.reject { |document| document.issues.empty? }
  return structural_conflict(request, documents, unsafe) unless unsafe.empty?
  return unmanaged_conflict(request, documents) unless unmanaged_unchanged?(documents)

  decisions = three_way_decisions(documents)
  conflicts = decisions.select(&:conflict)
  return render_conflicts(request, documents, decisions, conflicts) unless conflicts.empty?

  render_composite(request, documents, decisions)
end

#provider_idString

Returns:

  • (String)


35
# File 'lib/psych/merge/provider.rb', line 35

def provider_id = 'ruby.yaml.psych'