Class: DomainSanity::Subject
- Inherits:
-
Object
- Object
- DomainSanity::Subject
- Defined in:
- lib/domain_sanity/subject.rb,
lib/domain_sanity/subject.rb
Overview
A classified view of one subject string. Subject.for inspects the input once and returns the concrete type that fits it - Hostname, Wildcard, IPSubject, ReverseZone, or MalformedSubject - so a method that only makes sense for one kind (registrable_domain for a host, public? for an IP) lives only on that type instead of returning nil on a god-object.
Facts are computed lazily and memoized, so asking one question is cheap and
asking many re-parses nothing. valid? means the same thing on every
subject and matches DomainSanity.valid? exactly: true only for a
structurally valid plain host name. Wildcards, IPs, and reverse zones are
not "valid" in that sense and expose their own predicates instead.
Direct Known Subclasses
Hostname, IPSubject, MalformedSubject, ReverseZone, Wildcard
Constant Summary collapse
- TYPES =
{ hostname: Hostname, wildcard: Wildcard, ip: IPSubject, reverse_zone: ReverseZone }.freeze
Instance Attribute Summary collapse
-
#input ⇒ Object
readonly
Returns the value of attribute input.
-
#policy ⇒ Object
readonly
Returns the value of attribute policy.
Class Method Summary collapse
-
.for(input, policy: :ca_baseline) ⇒ Object
Classify
inputunderpolicy(a preset symbol, Hash, or Policy) and return the matching Subject subclass.
Instance Method Summary collapse
- #ascii ⇒ Object
- #hostname? ⇒ Boolean
-
#initialize(input, normalized, policy) ⇒ Subject
constructor
A new instance of Subject.
- #ip? ⇒ Boolean
- #kind ⇒ Object
- #punycode? ⇒ Boolean
- #reasons ⇒ Object
- #reverse_zone? ⇒ Boolean
-
#to_h ⇒ Object
A uniform snapshot: every subject exposes the same keys, with nil where a fact does not apply to this kind.
-
#type_facts ⇒ Object
Kind-specific overrides for the optional to_h slots.
- #unicode ⇒ Object
-
#valid? ⇒ Boolean
Only a structurally valid plain host name is "valid"; every other kind overrides nothing and stays false.
- #valid_wildcard? ⇒ Boolean
- #wildcard? ⇒ Boolean
Constructor Details
#initialize(input, normalized, policy) ⇒ Subject
Returns a new instance of Subject.
32 33 34 35 36 |
# File 'lib/domain_sanity/subject.rb', line 32 def initialize(input, normalized, policy) @input = input @norm = normalized @policy = policy end |
Instance Attribute Details
#input ⇒ Object (readonly)
Returns the value of attribute input.
21 22 23 |
# File 'lib/domain_sanity/subject.rb', line 21 def input @input end |
#policy ⇒ Object (readonly)
Returns the value of attribute policy.
21 22 23 |
# File 'lib/domain_sanity/subject.rb', line 21 def policy @policy end |
Class Method Details
.for(input, policy: :ca_baseline) ⇒ Object
Classify input under policy (a preset symbol, Hash, or Policy) and
return the matching Subject subclass.
25 26 27 28 29 30 |
# File 'lib/domain_sanity/subject.rb', line 25 def self.for(input, policy: :ca_baseline) pol = Policy.coerce(policy) norm = Name.normalize(input, pol) klass = TYPES.fetch(norm.kind, MalformedSubject) klass.new(input, norm, pol) end |
Instance Method Details
#ascii ⇒ Object
78 79 80 81 82 |
# File 'lib/domain_sanity/subject.rb', line 78 def ascii return @ascii if defined?(@ascii) @ascii = IDN.to_ascii(@input) end |
#hostname? ⇒ Boolean
48 49 50 |
# File 'lib/domain_sanity/subject.rb', line 48 def hostname? false end |
#ip? ⇒ Boolean
60 61 62 |
# File 'lib/domain_sanity/subject.rb', line 60 def ip? false end |
#kind ⇒ Object
38 39 40 |
# File 'lib/domain_sanity/subject.rb', line 38 def kind @norm.kind end |
#punycode? ⇒ Boolean
72 73 74 75 76 |
# File 'lib/domain_sanity/subject.rb', line 72 def punycode? return @punycode if defined?(@punycode) @punycode = IDN.punycode?(@input) end |
#reasons ⇒ Object
68 69 70 |
# File 'lib/domain_sanity/subject.rb', line 68 def reasons @reasons ||= Name.reasons_for(@norm, policy: @policy).freeze end |
#reverse_zone? ⇒ Boolean
64 65 66 |
# File 'lib/domain_sanity/subject.rb', line 64 def reverse_zone? false end |
#to_h ⇒ Object
A uniform snapshot: every subject exposes the same keys, with nil where a
fact does not apply to this kind. (The typed methods stay kind-specific -
an IPSubject still has no #registrable_domain - but the serialized shape is
stable so downstream present?/dig checks work the same for any kind.)
Subclasses fill the optional slots via #type_facts.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/domain_sanity/subject.rb', line 95 def to_h { input: @input, kind: kind, valid: valid?, wildcard: wildcard?, valid_wildcard: valid_wildcard?, ip: ip?, reserved_ip: nil, public_ip: nil, reverse_zone: reverse_zone?, punycode: punycode?, ascii: ascii, unicode: unicode, registrable_domain: nil, public_suffix: nil, reasons: reasons.map(&:to_s) }.merge(type_facts) end |
#type_facts ⇒ Object
Kind-specific overrides for the optional to_h slots. Base has none.
116 117 118 |
# File 'lib/domain_sanity/subject.rb', line 116 def type_facts {} end |
#unicode ⇒ Object
84 85 86 87 88 |
# File 'lib/domain_sanity/subject.rb', line 84 def unicode return @unicode if defined?(@unicode) @unicode = IDN.to_unicode(@input) end |
#valid? ⇒ Boolean
Only a structurally valid plain host name is "valid"; every other kind overrides nothing and stays false. See Hostname.
44 45 46 |
# File 'lib/domain_sanity/subject.rb', line 44 def valid? false end |
#valid_wildcard? ⇒ Boolean
56 57 58 |
# File 'lib/domain_sanity/subject.rb', line 56 def valid_wildcard? false end |
#wildcard? ⇒ Boolean
52 53 54 |
# File 'lib/domain_sanity/subject.rb', line 52 def wildcard? false end |