Class: Html2rss::Status

Inherits:
Data
  • Object
show all
Defined in:
lib/html2rss/status.rb

Overview

Shared RSS generator / JSON Feed user_comment formatter string.

Exposed publicly via FeedResult#status. Safe to log without reading articles. Stable telemetry payload for cross-repo consumers (e.g. html2rss-web observability). Tallies and counters are validated and frozen at construction (including Marshal load).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version:, scraper_tallies:, dedup_dropped:, selected_strategy: nil, attempt_count: 0, strategy_attempts: [], admission_drops: {}, entry_url: nil, scrape_url: nil, entry_resolution: nil) ⇒ Status

rubocop:disable Metrics/ParameterLists, Metrics/MethodLength -- Status Data.define members

Parameters:

  • version (String)
  • scraper_tallies (Hash{String => Integer})
  • dedup_dropped (Integer)
  • selected_strategy (Symbol, nil) (defaults to: nil)
  • attempt_count (Integer) (defaults to: 0)
  • strategy_attempts (Array<Hash>) (defaults to: [])
  • admission_drops (Hash{String => Integer}) (defaults to: {})
  • entry_url (String, nil) (defaults to: nil)
  • scrape_url (String, nil) (defaults to: nil)
  • entry_resolution (Hash, nil) (defaults to: nil)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/html2rss/status.rb', line 69

def initialize(
  version:, scraper_tallies:, dedup_dropped:, selected_strategy: nil, attempt_count: 0,
  strategy_attempts: [], admission_drops: {}, entry_url: nil, scrape_url: nil, entry_resolution: nil
)
  dedup = Integer(dedup_dropped)
  attempts = Integer(attempt_count)
  validate_counters!(dedup:, attempts:, selected_strategy:)

  super(
    version: version.to_s.dup.freeze,
    scraper_tallies: freeze_tallies(scraper_tallies),
    dedup_dropped: dedup,
    selected_strategy:,
    attempt_count: attempts,
    strategy_attempts: freeze_attempts(strategy_attempts),
    admission_drops: freeze_tallies(admission_drops),
    entry_url: freeze_optional_string(entry_url),
    scrape_url: freeze_optional_string(scrape_url),
    entry_resolution: freeze_entry_resolution(entry_resolution)
  )
end

Instance Attribute Details

#admission_dropsObject (readonly)

Returns the value of attribute admission_drops

Returns:

  • (Object)

    the current value of admission_drops



10
11
12
# File 'lib/html2rss/status.rb', line 10

def admission_drops
  @admission_drops
end

#attempt_countObject (readonly)

Returns the value of attribute attempt_count

Returns:

  • (Object)

    the current value of attempt_count



10
11
12
# File 'lib/html2rss/status.rb', line 10

def attempt_count
  @attempt_count
end

#dedup_droppedObject (readonly)

Returns the value of attribute dedup_dropped

Returns:

  • (Object)

    the current value of dedup_dropped



10
11
12
# File 'lib/html2rss/status.rb', line 10

def dedup_dropped
  @dedup_dropped
end

#entry_resolutionObject (readonly)

Returns the value of attribute entry_resolution

Returns:

  • (Object)

    the current value of entry_resolution



10
11
12
# File 'lib/html2rss/status.rb', line 10

def entry_resolution
  @entry_resolution
end

#entry_urlObject (readonly)

Returns the value of attribute entry_url

Returns:

  • (Object)

    the current value of entry_url



10
11
12
# File 'lib/html2rss/status.rb', line 10

def entry_url
  @entry_url
end

#scrape_urlObject (readonly)

Returns the value of attribute scrape_url

Returns:

  • (Object)

    the current value of scrape_url



10
11
12
# File 'lib/html2rss/status.rb', line 10

def scrape_url
  @scrape_url
end

#scraper_talliesObject (readonly)

Returns the value of attribute scraper_tallies

Returns:

  • (Object)

    the current value of scraper_tallies



10
11
12
# File 'lib/html2rss/status.rb', line 10

def scraper_tallies
  @scraper_tallies
end

#selected_strategyObject (readonly)

Returns the value of attribute selected_strategy

Returns:

  • (Object)

    the current value of selected_strategy



10
11
12
# File 'lib/html2rss/status.rb', line 10

def selected_strategy
  @selected_strategy
end

#strategy_attemptsObject (readonly)

Returns the value of attribute strategy_attempts

Returns:

  • (Object)

    the current value of strategy_attempts



10
11
12
# File 'lib/html2rss/status.rb', line 10

def strategy_attempts
  @strategy_attempts
end

#versionObject (readonly)

Returns the value of attribute version

Returns:

  • (Object)

    the current value of version



10
11
12
# File 'lib/html2rss/status.rb', line 10

def version
  @version
end

Class Method Details

.build(articles:, dedup_dropped: 0, selected_strategy: nil, attempt_count: 0, strategy_attempts: [], admission_drops: {}, scrape_target: nil, entry_url: nil, scrape_url: nil, entry_resolution: nil) ⇒ Html2rss::Status

Builds status from extracted articles and scrape telemetry.

rubocop:disable Metrics/ParameterLists, Metrics/MethodLength -- Status kwargs stay co-located

Parameters:

  • articles (Array<Html2rss::Article>)

    articles kept after deduplication

  • dedup_dropped (Integer) (defaults to: 0)

    number of articles removed by deduplication

  • selected_strategy (Symbol, nil) (defaults to: nil)

    concrete strategy that succeeded under :auto (else nil)

  • attempt_count (Integer) (defaults to: 0)

    auto-fallback attempt count (0 when not under :auto)

  • strategy_attempts (Array<Hash>) (defaults to: [])

    auto-fallback attempt hashes (empty outside :auto)

  • admission_drops (Hash{String => Integer}) (defaults to: {})

    Cleanup reason → count (empty when unused)

  • scrape_target (Html2rss::ScrapeTarget, nil) (defaults to: nil)

    domain URL pair (mapped to wire strings)

  • entry_url (String, nil) (defaults to: nil)

    original channel URL when entry resolution ran

  • scrape_url (String, nil) (defaults to: nil)

    effective scrape URL after resolution

  • entry_resolution (Html2rss::FeedResolution::Diag, Hash, nil) (defaults to: nil)

    resolution diagnostics

Returns:



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/html2rss/status.rb', line 30

def build(articles:, dedup_dropped: 0, selected_strategy: nil, attempt_count: 0,
          strategy_attempts: [], admission_drops: {}, scrape_target: nil,
          entry_url: nil, scrape_url: nil, entry_resolution: nil)
  tallies = articles.filter_map(&:scraper).tally.transform_keys { |klass| scraper_name(klass) }
  new(
    version: Html2rss::VERSION,
    scraper_tallies: tallies,
    dedup_dropped:,
    selected_strategy:,
    attempt_count:,
    strategy_attempts:,
    admission_drops:,
    entry_url: entry_url || scrape_target&.entry_url,
    scrape_url: scrape_url || scrape_target&.effective_url,
    entry_resolution:
  )
end

.scraper_name(klass) ⇒ String

Returns short scraper label for tallies / generator text.

Parameters:

  • klass (Class, #to_s)

    scraper class

Returns:

  • (String)

    short scraper label for tallies / generator text



52
53
54
# File 'lib/html2rss/status.rb', line 52

def scraper_name(klass)
  klass.to_s.gsub(/(?:Html2rss|Scraper)::/, '')
end

Instance Method Details

#to_generator_commentString

Formats the RSS generator string and JSON Feed user_comment. Scraper-focused only — auto strategy summary stays on #to_h, not this string. Omits the (scrapers: …) clause when tallies are empty.

Returns:

  • (String)


119
120
121
122
123
124
# File 'lib/html2rss/status.rb', line 119

def to_generator_comment
  return "html2rss V. #{version}" if scraper_tallies.empty?

  counts = scraper_tallies.map { |name, count| "#{name} (#{count})" }
  "html2rss V. #{version} (scrapers: #{counts.join(', ')})"
end

#to_hHash{Symbol => Object}

Observability hash for web (+scraper_status+). Omits empty/absent optional keys.

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity -- omit-empty optional keys stay explicit

Returns:

  • (Hash{Symbol => Object})


97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/html2rss/status.rb', line 97

def to_h
  {
    version:,
    dedup_dropped:,
    **(scraper_tallies.any? ? { scraper_tallies: } : {}),
    **(selected_strategy.nil? ? {} : { selected_strategy: }),
    **(attempt_count.positive? ? { attempt_count: } : {}),
    **(strategy_attempts.any? ? { strategy_attempts: } : {}),
    **(admission_drops.any? ? { admission_drops: } : {}),
    **(entry_url ? { entry_url: } : {}),
    **(scrape_url ? { scrape_url: } : {}),
    **(entry_resolution ? { entry_resolution: } : {})
  }
end