stable 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/stable/spec.rb +20 -9
  3. data/lib/stable.rb +21 -2
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4375cbe65cd2bf8c245d6415fbf69f7a3d52089e625f9c5d60d776db18bb8e7
4
- data.tar.gz: 73a10041d5fcd9d1c156b62081f477aada4bc8a61fa1fc3fe4b50a102358dba1
3
+ metadata.gz: fbfe47a4e34cd7aa98e7c0cdfa165adcb2612bb7d3e416ff30395239215df9df
4
+ data.tar.gz: 40ea2eef27e201637b20bd88d722d1bf01cad66fd84faed5ca6b9573c2124074
5
5
  SHA512:
6
- metadata.gz: d19ad046cd24e28cbb20ef92e23406dff44cc0f798d09a5c1b921d98d48f5edcb7c3dce7180484e535b32ff46ce14e5dddd68e3306d18dc15641069cca39786a
7
- data.tar.gz: 4e05508756de9a0cca55277846f630a54a638504594de3ddd9b024da4f6cd78815407918a610f8800c623552f5b7cbb642fda714176ac680e952ecbda39d91b5
6
+ metadata.gz: a33475e16728dbb9bf94f6de1807c7157d4b8edabf4a6f8bb67dac10c800a9b092a36ff66a26e8a50da6399e1c83c571edcfc843b613a34e1e898345b7797e2e
7
+ data.tar.gz: 7ed53b7619f0b5644f16f215cc6ed1a3e9ecb949741cb953edca5447784e2cbc71661890217e32674182a1614af4d5e33fd9ee845ada6e1b61fc934528625a46
data/lib/stable/spec.rb CHANGED
@@ -1,14 +1,16 @@
1
1
  # lib/stable/spec.rb
2
2
  require 'json'
3
+ require 'securerandom'
4
+ require 'digest'
3
5
 
4
6
  module Stable
5
7
  # a spec is a recording of a single method call, including the inputs and
6
8
  # outputs. it's a self-contained, serializable representation of a method's
7
9
  # behavior at a specific point in time.
8
10
  class Spec
9
- attr_reader :class_name, :method_name, :args, :result, :error, :timestamp, :actual_result, :actual_error, :status
11
+ attr_reader :class_name, :method_name, :args, :result, :error, :timestamp, :actual_result, :actual_error, :status, :uuid, :signature
10
12
 
11
- def initialize(class_name:, method_name:, args:, result: nil, error: nil, timestamp: Time.now.iso8601)
13
+ def initialize(class_name:, method_name:, args:, result: nil, error: nil, timestamp: Time.now.iso8601, uuid: SecureRandom.uuid)
12
14
  @class_name = class_name
13
15
  @method_name = method_name
14
16
  @args = args
@@ -16,6 +18,8 @@ module Stable
16
18
  @error = error
17
19
  @timestamp = timestamp
18
20
  @status = :pending
21
+ @uuid = uuid
22
+ @signature = Digest::SHA256.hexdigest("#{class_name}##{method_name}:#{args.to_json}")
19
23
  end
20
24
 
21
25
  def run!
@@ -43,14 +47,18 @@ module Stable
43
47
  end
44
48
 
45
49
  def to_s
46
- description = "#{class_name}##{method_name}(#{args.join(', ')})"
50
+ short_uuid = uuid.split('-').last
51
+ short_sig = signature[0..6]
52
+ desc = "#{short_uuid}/#{short_sig}"
53
+ call = "#{class_name}##{method_name}(#{args.join(', ')})"
54
+
47
55
  case status
48
56
  when :passed
49
- "PASSED: #{description}"
57
+ "#{desc} P #{call}"
50
58
  when :passed_with_error
51
- "PASSED: #{description} (error)"
59
+ "#{desc} P (error) #{call}"
52
60
  when :failed
53
- lines = ["FAILED: #{description}"]
61
+ lines = ["#{desc} F #{call}"]
54
62
  if actual_error
55
63
  if error
56
64
  lines << " Expected error: #{error['class']}"
@@ -70,7 +78,7 @@ module Stable
70
78
  end
71
79
  lines.join("\n")
72
80
  else
73
- "PENDING: #{description}"
81
+ "#{desc} ? #{call}"
74
82
  end
75
83
  end
76
84
 
@@ -81,7 +89,9 @@ module Stable
81
89
  args: args,
82
90
  result: result,
83
91
  error: error,
84
- timestamp: timestamp
92
+ timestamp: timestamp,
93
+ uuid: uuid,
94
+ signature: signature
85
95
  }.compact.to_json
86
96
  end
87
97
 
@@ -93,7 +103,8 @@ module Stable
93
103
  args: data['args'],
94
104
  result: data['result'],
95
105
  error: data['error'],
96
- timestamp: data['timestamp']
106
+ timestamp: data['timestamp'],
107
+ uuid: data['uuid']
97
108
  )
98
109
  end
99
110
  end
data/lib/stable.rb CHANGED
@@ -37,7 +37,10 @@ module Stable
37
37
  args: args,
38
38
  result: result
39
39
  )
40
- Stable.storage.puts(spec.to_jsonl)
40
+ unless Stable.send(:_spec_exists?, spec.signature)
41
+ Stable.storage.puts(spec.to_jsonl)
42
+ Stable.send(:_recorded_specs) << spec
43
+ end
41
44
  result
42
45
  rescue => e
43
46
  spec = Spec.new(
@@ -50,7 +53,10 @@ module Stable
50
53
  backtrace: e.backtrace
51
54
  }
52
55
  )
53
- Stable.storage.puts(spec.to_jsonl)
56
+ unless Stable.send(:_spec_exists?, spec.signature)
57
+ Stable.storage.puts(spec.to_jsonl)
58
+ Stable.send(:_recorded_specs) << spec
59
+ end
54
60
  raise e
55
61
  end
56
62
  else
@@ -64,5 +70,18 @@ module Stable
64
70
  def verify(record_hash)
65
71
  Spec.from_jsonl(record_hash.to_json).run!
66
72
  end
73
+
74
+ private
75
+
76
+ def _recorded_specs
77
+ @_recorded_specs ||= begin
78
+ return [] unless storage.respond_to?(:path) && File.exist?(storage.path)
79
+ File.foreach(storage.path).map { |line| Spec.from_jsonl(line) }
80
+ end
81
+ end
82
+
83
+ def _spec_exists?(signature)
84
+ _recorded_specs.any? { |spec| spec.signature == signature }
85
+ end
67
86
  end
68
87
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Lunt