bogo 0.2.14 → 0.2.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 730a00461fb1d2b71a79a959bec8085111781a1ac542443566f875f9c9560e45
4
- data.tar.gz: 7225927bd86221c434caf7f9808f87c17c7b71a1e7839ec172157521876bf551
3
+ metadata.gz: '005490ecb547fbeb1d4b941787e8a963c3c17ac8403527deb3ed6b33614312da'
4
+ data.tar.gz: f6c08b295196223458fa8649fd2224d8f46cd0e641545bed5c4173bdccda8c88
5
5
  SHA512:
6
- metadata.gz: c3351892aae400d4035470522093bd231f6611d8e955338ac29af84d7ff594b498b863ee63fce80272b42cb3aa3bb4e13e32f3c95f67fe6c66c73ea8ac8cdfed
7
- data.tar.gz: a9cac6cfbb9df030f965ca3e6d180343ba8445a1bbffd7ea029b02a45dc05f4846d81211e5ba3c8cbc2a99b83c4683715e3e62179c1e879c9a866502692ca49d
6
+ metadata.gz: a501ec13801d316df3d9fccec43bb86dbb6b3cb4847fc6645b266aeff41bebd51107090b733287650badbe038cfeb37cb59a6254fa366b74a65a3c4dce4b38e9
7
+ data.tar.gz: 25ff9327f54f0b8f3d4602e9834d87548a959f14a767fa9243d75037fe542efbc83eae002ca6dd9e2e461b2dda8c474d84bbcb4f0b1699aebfe551b5f86ae251
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # v0.2.16
2
+ * [Lazy] Fix synchronization (#8)
3
+ * [Memoization] Check for data before deleting
4
+
5
+ # v0.2.15
6
+ * [Logger] Fix frozen string modification (#6)
7
+ * [Stack] Add stack
8
+
1
9
  # v0.2.14
2
10
  * [Logger] Add logging helpers
3
11
 
data/CONTRIBUTING.md CHANGED
@@ -1,22 +1,18 @@
1
1
  # Contributing
2
2
 
3
- ## Branches
3
+ ## Fixes
4
4
 
5
- ### `master` branch
5
+ Have a fix to some bug you want to submit? Well you're
6
+ awesome. Please just include a description of the bug
7
+ (or link to originating issue) and test coverage on the
8
+ modifications.
6
9
 
7
- The master branch is the current stable released version.
10
+ ## New Features
8
11
 
9
- ### `develop` branch
10
-
11
- The develop branch is the current edge of development.
12
-
13
- ## Pull requests
14
-
15
- * https://github.com/spox/bogo/pulls
16
-
17
- Please base all pull requests of the `develop` branch. Merges to
18
- `master` only occur through the `develop` branch. Pull requests
19
- based on `master` will likely be cherry picked.
12
+ Have a new feature you want to add? Well you're awesome
13
+ too! It may be a good idea to submit an issue first to
14
+ describe the desired feature and get any feedback. Please
15
+ be sure to include tests.
20
16
 
21
17
  ## Issues
22
18
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Chris Roberts
1
+ Copyright 2022 Chris Roberts
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
@@ -10,4 +10,4 @@
10
10
  distributed under the License is distributed on an "AS IS" BASIS,
11
11
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  See the License for the specific language governing permissions and
13
- limitations under the License.
13
+ limitations under the License.
data/bogo.gemspec CHANGED
@@ -12,9 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.license = "Apache 2.0"
13
13
  s.add_runtime_dependency "hashie"
14
14
  s.add_runtime_dependency "multi_json"
15
- s.add_runtime_dependency "concurrent-ruby", "~> 1.1.3"
16
15
  s.add_development_dependency "pry"
17
16
  s.add_development_dependency "minitest"
18
- s.add_development_dependency "rake", "~> 10"
17
+ s.add_development_dependency "rake"
19
18
  s.files = Dir["lib/**/*"] + %w(bogo.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
20
19
  end
@@ -1,5 +1,3 @@
1
- require 'bogo'
2
-
3
1
  module Bogo
4
2
  # Animal stylings on strings
5
3
  module AnimalStrings
@@ -24,7 +22,5 @@ module Bogo
24
22
  def snake(string)
25
23
  string.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').gsub('-', '_').downcase
26
24
  end
27
-
28
25
  end
29
-
30
26
  end
@@ -1,10 +1,6 @@
1
- require 'bogo'
2
-
3
1
  module Bogo
4
-
5
2
  # Constant helper
6
3
  module Constants
7
-
8
4
  # Convert string to constant
9
5
  #
10
6
  # @param string [String] full constant name
@@ -40,7 +36,5 @@ module Bogo
40
36
  constantize(klass.join('::'))
41
37
  end
42
38
  end
43
-
44
39
  end
45
-
46
40
  end
@@ -1,15 +1,12 @@
1
- require 'bogo'
2
1
  require 'tempfile'
3
2
 
4
3
  module Bogo
5
4
  # Tempfile that will destroy itself when closed
6
5
  class EphemeralFile < Tempfile
7
-
8
6
  # Override to remove file after close
9
7
  def close
10
8
  super
11
9
  delete
12
10
  end
13
-
14
11
  end
15
12
  end
@@ -7,7 +7,6 @@ require 'http/request'
7
7
  # library to allow easy sharing. It is the responsibility of the user
8
8
  # to ensure the http gem is available!
9
9
  class HTTP::Request
10
-
11
10
  # Override to implicitly apply proxy as required
12
11
  #
13
12
  # NOTE: If dealing with https request, force port so CONNECT request
@@ -54,5 +53,4 @@ class HTTP::Request
54
53
  end
55
54
  "CONNECT #{@uri.host}:#{dest_port} HTTP/#{version}"
56
55
  end
57
-
58
56
  end
data/lib/bogo/lazy.rb CHANGED
@@ -1,21 +1,32 @@
1
- require 'bogo'
2
1
  require 'multi_json'
2
+ require 'monitor'
3
3
  require 'digest/sha2'
4
4
 
5
5
  module Bogo
6
6
  # Adds functionality to facilitate laziness
7
7
  module Lazy
8
-
9
8
  # Instance methods for laziness
10
9
  module InstanceMethods
11
10
 
11
+ def self.included(klass)
12
+ klass.include(MonitorMixin)
13
+ klass.instance_variable_set(:@calling_on_missing, false)
14
+ end
15
+
16
+ # @return [Monitor] Monitor instance for synchronization
17
+ def _mon
18
+ @mon ||= Monitor.new
19
+ end
20
+
12
21
  # @return [Smash] argument hash
13
22
  def data
14
- unless(@data)
15
- @data = Smash.new
16
- self.class.attributes.each do |key, value|
17
- if(value.has_key?('default'))
18
- @data[key] = value['default']
23
+ _mon.synchronize do
24
+ unless(@data)
25
+ @data = Smash.new
26
+ self.class.attributes.each do |key, value|
27
+ if(value.has_key?('default'))
28
+ @data[key] = value['default']
29
+ end
19
30
  end
20
31
  end
21
32
  end
@@ -24,15 +35,17 @@ module Bogo
24
35
 
25
36
  # @return [Smash] updated data
26
37
  def dirty
27
- unless(@dirty)
28
- @dirty = Smash.new
38
+ _mon.synchronize do
39
+ unless(@dirty)
40
+ @dirty = Smash.new
41
+ end
29
42
  end
30
43
  @dirty
31
44
  end
32
45
 
33
46
  # @return [Smash] current data state
34
47
  def attributes
35
- data.merge(dirty)
48
+ _mon.synchronize { data.merge(dirty) }
36
49
  end
37
50
 
38
51
  # Create new instance
@@ -40,20 +53,22 @@ module Bogo
40
53
  # @param args [Hash]
41
54
  # @return [self]
42
55
  def load_data(args={})
43
- args = args.to_smash
44
- @data = Smash.new
45
- self.class.attributes.each do |name, options|
46
- val = args[name]
47
- if(options[:required] && !args.has_key?(name) && !options.has_key?(:default))
48
- raise ArgumentError.new("Missing required option: `#{name}`")
49
- end
50
- if(val.nil? && !args.has_key?(name) && options[:default])
51
- if(options[:default])
52
- val = options[:default].respond_to?(:call) ? options[:default].call : options[:default]
56
+ _mon.synchronize do
57
+ args = args.to_smash
58
+ @data = Smash.new
59
+ self.class.attributes.each do |name, options|
60
+ val = args[name]
61
+ if(options[:required] && !args.has_key?(name) && !options.has_key?(:default))
62
+ raise ArgumentError.new("Missing required option: `#{name}`")
63
+ end
64
+ if(val.nil? && !args.has_key?(name) && options[:default])
65
+ if(options[:default])
66
+ val = options[:default].respond_to?(:call) ? options[:default].call : options[:default]
67
+ end
68
+ end
69
+ if(args.has_key?(name) || val)
70
+ self.send("#{name}=", val)
53
71
  end
54
- end
55
- if(args.has_key?(name) || val)
56
- self.send("#{name}=", val)
57
72
  end
58
73
  end
59
74
  self
@@ -65,9 +80,11 @@ module Bogo
65
80
  #
66
81
  # @return [self]
67
82
  def valid_state
68
- data.merge!(dirty)
69
- dirty.clear
70
- @_checksum = Digest::SHA256.hexdigest(MultiJson.dump(data.inspect).to_s)
83
+ _mon.synchronize do
84
+ data.merge!(dirty)
85
+ dirty.clear
86
+ @_checksum = Digest::SHA256.hexdigest(MultiJson.dump(data.inspect).to_s)
87
+ end
71
88
  self
72
89
  end
73
90
 
@@ -76,14 +93,16 @@ module Bogo
76
93
  # @param attr [String, Symbol] name of attribute
77
94
  # @return [TrueClass, FalseClass] model or attribute is dirty
78
95
  def dirty?(attr=nil)
79
- if(attr)
80
- dirty.has_key?(attr)
81
- else
82
- if(@_checksum)
83
- !dirty.empty? ||
84
- @_checksum != Digest::SHA256.hexdigest(MultiJson.dump(data.inspect).to_s)
96
+ _mon.synchronize do
97
+ if(attr)
98
+ dirty.has_key?(attr)
85
99
  else
86
- true
100
+ if(@_checksum)
101
+ !dirty.empty? ||
102
+ @_checksum != Digest::SHA256.hexdigest(MultiJson.dump(data.inspect).to_s)
103
+ else
104
+ true
105
+ end
87
106
  end
88
107
  end
89
108
  end
@@ -100,19 +119,20 @@ module Bogo
100
119
 
101
120
  # @return [Hash]
102
121
  def to_h
103
- Hash[
104
- attributes.map{|k,v|
105
- [k, v.is_a?(Array) ?
106
- v.map{|x| x.respond_to?(:to_h) ? x.to_h : x} :
107
- v.respond_to?(:to_h) ? v.to_h : v]
108
- }
109
- ]
122
+ _mon.synchronize do
123
+ Hash[
124
+ attributes.map{|k,v|
125
+ [k, v.is_a?(Array) ?
126
+ v.map{|x| x.respond_to?(:to_h) ? x.to_h : x} :
127
+ v.respond_to?(:to_h) ? v.to_h : v]
128
+ }
129
+ ]
130
+ end
110
131
  end
111
132
  end
112
133
 
113
134
  # Class methods for laziness
114
135
  module ClassMethods
115
-
116
136
  # Disable dirty state
117
137
  def always_clean!
118
138
  self.class_eval do
@@ -264,11 +284,9 @@ module Bogo
264
284
  @attributes = attrs.to_smash
265
285
  true
266
286
  end
267
-
268
287
  end
269
288
 
270
289
  class << self
271
-
272
290
  # Injects laziness into class
273
291
  #
274
292
  # @param klass [Class]
@@ -278,16 +296,12 @@ module Bogo
278
296
  extend ClassMethods
279
297
 
280
298
  class << self
281
-
282
299
  def inherited(klass)
283
300
  klass.set_attributes(self.attributes.to_smash)
284
301
  end
285
-
286
302
  end
287
303
  end
288
304
  end
289
-
290
305
  end
291
-
292
306
  end
293
307
  end
data/lib/bogo/logger.rb CHANGED
@@ -1,4 +1,3 @@
1
- require "concurrent"
2
1
  require "logger"
3
2
 
4
3
  module Bogo
@@ -46,9 +45,9 @@ module Bogo
46
45
  logger_args = [$stderr]
47
46
  end
48
47
  @base_args = logger_args
49
- logger = ::Logger.new(*@base_args)
50
- logger.level = :fatal
51
- @wrapped_logger = Concurrent::MVar.new(logger)
48
+ @logger = ::Logger.new(*@base_args)
49
+ @logger.level = :fatal
50
+ @lock = Mutex.new
52
51
  end
53
52
 
54
53
  # Create a new logger with the sub-name provided
@@ -56,7 +55,7 @@ module Bogo
56
55
  # @param name [String] sub-name for logger
57
56
  # @return [Logger]
58
57
  def named(name)
59
- new_name = self.progname.to_s
58
+ new_name = self.progname.to_s.dup
60
59
  new_name << "." unless new_name.empty?
61
60
  new_name << name
62
61
  new_logger = Logger.new(*@base_args)
@@ -71,15 +70,9 @@ module Bogo
71
70
  next if l_m.to_s.start_with?("_") || l_m.to_s == "object_id"
72
71
  class_eval <<-EOC
73
72
  def #{l_m}(*ma, &mb)
74
- wrapped_logger.borrow { |l| l.send(:#{l_m}, *ma, &mb) }
73
+ @lock.synchronize { @logger.send(:#{l_m}, *ma, &mb) }
75
74
  end
76
75
  EOC
77
76
  end
78
-
79
- protected
80
-
81
- def wrapped_logger
82
- @wrapped_logger
83
- end
84
77
  end
85
78
  end
@@ -1,16 +1,12 @@
1
- require 'bogo'
2
-
3
1
  module Bogo
4
2
  # Memoization helpers
5
3
  module Memoization
6
-
7
4
  # Lock for providing exclusive access
8
5
  EXCLUSIVE_LOCK = Mutex.new
9
6
  # Holder for global memoization items
10
7
  GLOBAL_MEMOS = Smash.new
11
8
 
12
9
  class << self
13
-
14
10
  # Clean up isolated memoizations
15
11
  #
16
12
  # @param object_id [Object]
@@ -19,7 +15,7 @@ module Bogo
19
15
  proc do
20
16
  Thread.current[:bogo_memoization].delete_if do |k,v|
21
17
  k.to_s.start_with?(object_id.to_s)
22
- end
18
+ end if Thread.current[:bogo_memoization].is_a?(Hash)
23
19
  end
24
20
  end
25
21
 
@@ -38,7 +34,6 @@ module Bogo
38
34
  GLOBAL_MEMOS.clear
39
35
  end
40
36
  end
41
-
42
37
  end
43
38
 
44
39
  # Memoize data
@@ -123,6 +118,5 @@ module Bogo
123
118
  end
124
119
  true
125
120
  end
126
-
127
121
  end
128
122
  end
@@ -1,10 +1,7 @@
1
- require 'bogo'
2
-
3
1
  module Bogo
4
2
  # Specialized priority based queue
5
3
  # @note does not allow duplicate objects to be queued
6
4
  class PriorityQueue
7
-
8
5
  # Create a new priority queue
9
6
  #
10
7
  # @return [self]
@@ -24,10 +21,12 @@ module Bogo
24
21
  def push(item, cost=nil, &block)
25
22
  lock.synchronize do
26
23
  if(queue[item])
27
- raise ArgumentError.new "Item already exists in queue. Items must be unique! (#{item})"
24
+ raise ArgumentError,
25
+ "Item already exists in queue. Items must be unique! (#{item})"
28
26
  end
29
27
  unless(cost || block_given?)
30
- raise ArgumentError.new 'Cost must be provided as parameter or block!'
28
+ raise ArgumentError,
29
+ 'Cost must be provided as parameter or block!'
31
30
  end
32
31
  @block_costs += 1 if cost.nil?
33
32
  queue[item] = cost || block
@@ -45,10 +44,12 @@ module Bogo
45
44
  items.each do |item_pair|
46
45
  item, cost = item_pair
47
46
  if(queue[item])
48
- raise ArgumentError.new "Item already exists in queue. Items must be unique! (#{item})"
47
+ raise ArgumentError,
48
+ "Item already exists in queue. Items must be unique! (#{item})"
49
49
  end
50
50
  unless(cost.is_a?(Numeric) || cost.is_a?(Proc))
51
- raise ArgumentError.new "Cost must be provided as parameter or proc! (item: #{item})"
51
+ raise ArgumentError,
52
+ "Cost must be provided as parameter or proc! (item: #{item})"
52
53
  end
53
54
  @block_costs += 1 if cost.is_a?(Proc)
54
55
  queue[item] = cost
@@ -106,7 +107,5 @@ module Bogo
106
107
  protected
107
108
 
108
109
  attr_reader :queue, :lock
109
-
110
110
  end
111
-
112
111
  end
data/lib/bogo/retry.rb CHANGED
@@ -1,10 +1,6 @@
1
- require 'bogo'
2
-
3
1
  module Bogo
4
-
5
2
  # Perform action and retry until successful or abort
6
3
  class Retry
7
-
8
4
  # Create a type of retry
9
5
  #
10
6
  # @param type [String, Symbol] name of retry type
@@ -38,7 +34,8 @@ module Bogo
38
34
  # @return [self]
39
35
  def initialize(args={}, &block)
40
36
  unless(block)
41
- raise ArgumentError.new 'Expecting block but no block was provided!'
37
+ raise ArgumentError,
38
+ 'Expecting block but no block was provided!'
42
39
  end
43
40
  args = args.to_smash
44
41
  @ui = args[:ui]
@@ -58,7 +55,8 @@ module Bogo
58
55
  # @return [Object] result of action
59
56
  def run!
60
57
  if(dead)
61
- raise RuntimeError.new "Action has already reached maximum allowed attempts (#{max_attempts})!"
58
+ raise RuntimeError,
59
+ "Action has already reached maximum allowed attempts (#{max_attempts})!"
62
60
  else
63
61
  begin
64
62
  log_attempt!
@@ -110,7 +108,6 @@ module Bogo
110
108
 
111
109
  # Flat retry implementation
112
110
  class Flat < Retry
113
-
114
111
  # @return [Numeric]
115
112
  attr_reader :wait_interval
116
113
 
@@ -133,12 +130,10 @@ module Bogo
133
130
  def wait_on_failure(*_)
134
131
  wait_interval
135
132
  end
136
-
137
133
  end
138
134
 
139
135
  # Linear retry implementation
140
136
  class Linear < Retry
141
-
142
137
  # @return [Numeric]
143
138
  attr_reader :wait_interval
144
139
 
@@ -161,12 +156,10 @@ module Bogo
161
156
  def wait_on_failure(*_)
162
157
  wait_interval * attempts
163
158
  end
164
-
165
159
  end
166
160
 
167
161
  # Exponential retry implementation
168
162
  class Exponential < Retry
169
-
170
163
  # @return [Numeric]
171
164
  attr_reader :wait_interval
172
165
  # @return [Numeric]
@@ -196,9 +189,6 @@ module Bogo
196
189
  def wait_on_failure(*_)
197
190
  retries == 0 ? wait_interval : (wait_interval + retries) ** wait_exponent
198
191
  end
199
-
200
192
  end
201
-
202
193
  end
203
-
204
194
  end
data/lib/bogo/smash.rb CHANGED
@@ -1,12 +1,9 @@
1
1
  require 'hashie'
2
2
  require 'digest/sha2'
3
- require 'bogo'
4
3
 
5
4
  module Bogo
6
-
7
5
  # Customized Hash
8
6
  class Smash < Hash
9
-
10
7
  class NoValue; end
11
8
  NO_VALUE = NoValue.new
12
9
 
@@ -25,7 +22,7 @@ module Bogo
25
22
  if(args.first.is_a?(::Hash))
26
23
  base = args.shift
27
24
  end
28
- super *args
25
+ super(*args)
29
26
  if(base)
30
27
  self.replace(base.to_smash)
31
28
  end
@@ -89,7 +86,8 @@ module Bogo
89
86
  elsif(args.size > 1)
90
87
  default_value = args.pop
91
88
  elsif(args.size < 1)
92
- raise ArgumentError.new("Default value must be provided for #fetch")
89
+ raise ArgumentError,
90
+ "Default value must be provided for #fetch"
93
91
  end
94
92
  result = retrieve(*args)
95
93
  if(result == NO_VALUE)
@@ -105,7 +103,8 @@ module Bogo
105
103
  # @return [Object] value set
106
104
  def set(*args)
107
105
  unless(args.size > 1)
108
- raise ArgumentError.new 'Set requires at least one key and a value'
106
+ raise ArgumentError,
107
+ 'Set requires at least one key and a value'
109
108
  end
110
109
  value = args.pop
111
110
  set_key = args.pop
@@ -132,13 +131,11 @@ module Bogo
132
131
  def checksum
133
132
  Digest::SHA256.hexdigest(self.to_smash(:sorted).to_s)
134
133
  end
135
-
136
134
  end
137
135
  end
138
136
 
139
137
  # Hook helper into toplevel `Hash`
140
138
  class Hash
141
-
142
139
  # Convert to Smash
143
140
  #
144
141
  # @return [Smash]
@@ -198,11 +195,9 @@ class Hash
198
195
  args.include?(:freeze) ? obj.freeze : obj
199
196
  end
200
197
  end
201
-
202
198
  end
203
199
 
204
200
  class Array
205
-
206
201
  # Iterates searching for Hash types to auto convert
207
202
  #
208
203
  # @return [Array]
@@ -215,7 +210,6 @@ class Array
215
210
  end
216
211
  end
217
212
  end
218
-
219
213
  end
220
214
 
221
215
  unless(defined?(Smash))