Class: JetstreamBridge::Models::Subject

Inherits:
Object
  • Object
show all
Defined in:
lib/jetstream_bridge/models/subject.rb

Overview

Value object representing a NATS subject

Examples:

Creating a subject

subject = Subject.source(env: "production", app_name: "api", dest: "worker")
subject.to_s # => "production.api.sync.worker"

Parsing a subject string

subject = Subject.parse("production.api.sync.worker")
subject.env         # => "production"
subject.source_app  # => "api"
subject.dest_app    # => "worker"

Constant Summary collapse

WILDCARD_SINGLE =
'*'
WILDCARD_MULTI =
'>'
SEPARATOR =
'.'
INVALID_CHARS =
/[#{Regexp.escape(WILDCARD_SINGLE + WILDCARD_MULTI + SEPARATOR)}]/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value) ⇒ Subject

Returns a new instance of Subject.



24
25
26
27
28
29
30
31
# File 'lib/jetstream_bridge/models/subject.rb', line 24

def initialize(value)
  @value = value.to_s
  @tokens = @value.split(SEPARATOR)
  validate!
  @value.freeze
  @tokens.freeze
  freeze
end

Instance Attribute Details

#tokensObject (readonly)

Returns the value of attribute tokens.



22
23
24
# File 'lib/jetstream_bridge/models/subject.rb', line 22

def tokens
  @tokens
end

#valueObject (readonly)

Returns the value of attribute value.



22
23
24
# File 'lib/jetstream_bridge/models/subject.rb', line 22

def value
  @value
end

Class Method Details

.destination(env:, source:, app_name:) ⇒ Object



38
39
40
# File 'lib/jetstream_bridge/models/subject.rb', line 38

def self.destination(env:, source:, app_name:)
  new("#{env}.#{source}.sync.#{app_name}")
end

.dlq(env:, app_name:) ⇒ Object



42
43
44
# File 'lib/jetstream_bridge/models/subject.rb', line 42

def self.dlq(env:, app_name:)
  new("#{env}.#{app_name}.sync.dlq")
end

.parse(string) ⇒ Subject

Parse a subject string into a Subject object with metadata

Parameters:

  • string (String)

    Subject string (e.g., “production.api.sync.worker”)

Returns:



50
51
52
# File 'lib/jetstream_bridge/models/subject.rb', line 50

def self.parse(string)
  new(string)
end

.source(env:, app_name:, dest:) ⇒ Object

Factory methods



34
35
36
# File 'lib/jetstream_bridge/models/subject.rb', line 34

def self.source(env:, app_name:, dest:)
  new("#{env}.#{app_name}.sync.#{dest}")
end

.validate_component!(value, name) ⇒ Object

Validate a component (env, app_name, etc.) for use in subjects

Raises:

  • (ArgumentError)


117
118
119
120
121
122
123
124
125
126
127
# File 'lib/jetstream_bridge/models/subject.rb', line 117

def self.validate_component!(value, name)
  str = value.to_s
  if str.match?(INVALID_CHARS)
    wildcards = "#{SEPARATOR}, #{WILDCARD_SINGLE}, #{WILDCARD_MULTI}"
    raise ArgumentError,
          "#{name} cannot contain NATS wildcards (#{wildcards}): #{value.inspect}"
  end
  raise ArgumentError, "#{name} cannot be empty" if str.strip.empty?

  true
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



106
107
108
# File 'lib/jetstream_bridge/models/subject.rb', line 106

def ==(other)
  @value == (other.is_a?(Subject) ? other.value : other.to_s)
end

#covered_by?(patterns) ⇒ Boolean

Check if covered by any pattern in a list

Returns:

  • (Boolean)


98
99
100
# File 'lib/jetstream_bridge/models/subject.rb', line 98

def covered_by?(patterns)
  SubjectMatcher.covered?(Array(patterns).map(&:to_s), @value)
end

#dest_appString?

Get destination application from subject

Returns:

  • (String, nil)

    Destination application



74
75
76
# File 'lib/jetstream_bridge/models/subject.rb', line 74

def dest_app
  @tokens[3]
end

#dlq?Boolean

Check if this is a DLQ subject

DLQ subjects follow the pattern: #env.app.sync.dlq

Returns:

  • (Boolean)

    True if this is a DLQ subject



83
84
85
# File 'lib/jetstream_bridge/models/subject.rb', line 83

def dlq?
  @tokens.length == 4 && @tokens[2] == 'sync' && @tokens[3] == 'dlq'
end

#envString?

Get environment from subject (first token)

Returns:

  • (String, nil)

    Environment



57
58
59
# File 'lib/jetstream_bridge/models/subject.rb', line 57

def env
  @tokens[0]
end

#hashObject



112
113
114
# File 'lib/jetstream_bridge/models/subject.rb', line 112

def hash
  @value.hash
end

#matches?(pattern) ⇒ Boolean

Check if this subject matches a pattern

Returns:

  • (Boolean)


88
89
90
# File 'lib/jetstream_bridge/models/subject.rb', line 88

def matches?(pattern)
  SubjectMatcher.match?(pattern.to_s, @value)
end

#overlaps?(other) ⇒ Boolean

Check if this subject overlaps with another

Returns:

  • (Boolean)


93
94
95
# File 'lib/jetstream_bridge/models/subject.rb', line 93

def overlaps?(other)
  SubjectMatcher.overlap?(@value, other.to_s)
end

#source_appString?

Get source application from subject

For regular subjects: #env.#source_app.sync.dest For DLQ subjects: #env.app_name.sync.dlq

Returns:

  • (String, nil)

    Source application



67
68
69
# File 'lib/jetstream_bridge/models/subject.rb', line 67

def source_app
  @tokens[1]
end

#to_sObject



102
103
104
# File 'lib/jetstream_bridge/models/subject.rb', line 102

def to_s
  @value
end