From a82e147cd5a91d84a248a1f9894442822e9e0626 Mon Sep 17 00:00:00 2001 From: akmhatey-ai <260399619+akmhatey-ai@users.noreply.github.com> Date: Mon, 25 May 2026 17:42:16 +0200 Subject: [PATCH] #479: add iterate since DSL --- lib/fbe/iterate.rb | 19 ++++++++++++++++ test/fbe/test_iterate.rb | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/lib/fbe/iterate.rb b/lib/fbe/iterate.rb index f570285..c6a6106 100644 --- a/lib/fbe/iterate.rb +++ b/lib/fbe/iterate.rb @@ -97,6 +97,7 @@ def initialize(fb:, loog:, options:, global:, epoch:, kickoff:) @kickoff = kickoff @label = nil @since = 0 + @custom = false @query = nil @sorting = nil @repeats = 1 @@ -148,6 +149,24 @@ def repeats(repeats) @repeats = repeats end + # Sets the initial marker value. + # + # This value is used when no marker fact exists yet, and when iteration + # restarts after the query returns nil. + # + # @param [Integer] value The initial marker value + # @return [nil] Nothing is returned + # @raise [RuntimeError] If value is nil, not an Integer, or already set + # @example Start scanning after issue 100 + # iterator.since(100) + def since(value) + raise(Fbe::Error, 'Since is already set') if @custom + raise(Fbe::Error, 'Cannot set "since" to nil') if value.nil? + raise(Fbe::Error, 'The "since" must be an Integer') unless value.is_a?(Integer) + @since = value + @custom = true + end + # Sets the query to execute for each iteration. # # The query can use two special variables: diff --git a/test/fbe/test_iterate.rb b/test/fbe/test_iterate.rb index 69db61f..6f9a175 100644 --- a/test/fbe/test_iterate.rb +++ b/test/fbe/test_iterate.rb @@ -191,6 +191,54 @@ def test_raises_when_repeats_is_not_positive end end + def test_configures_since_start + opts = Judges::Options.new(['repositories=foo/bar', 'testing=true']) + fb = Fbe.fb(fb: Factbase.new, global: {}, options: opts, loog: Loog::NULL) + seen = [] + Fbe.iterate(fb:, loog: Loog::NULL, global: {}, options: opts, epoch: Time.now, kickoff: Time.now) do + as('custom_since_test') + since(7) + by('(plus $before 1)') + repeats(1) + over do |_, nxt| + seen << nxt + nxt + end + end + assert_equal([8], seen) + end + + def test_raises_when_since_is_nil + opts = Judges::Options.new(['repositories=foo/bar', 'testing=true']) + fb = Fbe.fb(fb: Factbase.new, global: {}, options: opts, loog: Loog::NULL) + assert_raises(Fbe::Error) do + Fbe.iterate(fb:, loog: Loog::NULL, global: {}, options: opts, epoch: Time.now, kickoff: Time.now) do + since(nil) + end + end + end + + def test_raises_when_since_is_not_integer + opts = Judges::Options.new(['repositories=foo/bar', 'testing=true']) + fb = Fbe.fb(fb: Factbase.new, global: {}, options: opts, loog: Loog::NULL) + assert_raises(Fbe::Error) do + Fbe.iterate(fb:, loog: Loog::NULL, global: {}, options: opts, epoch: Time.now, kickoff: Time.now) do + since('7') + end + end + end + + def test_raises_when_since_set_twice + opts = Judges::Options.new(['repositories=foo/bar', 'testing=true']) + fb = Fbe.fb(fb: Factbase.new, global: {}, options: opts, loog: Loog::NULL) + assert_raises(Fbe::Error) do + Fbe.iterate(fb:, loog: Loog::NULL, global: {}, options: opts, epoch: Time.now, kickoff: Time.now) do + since(1) + since(2) + end + end + end + def test_raises_when_label_is_nil opts = Judges::Options.new(['repositories=foo/bar', 'testing=true']) fb = Fbe.fb(fb: Factbase.new, global: {}, options: opts, loog: Loog::NULL)