json_schematize 0.6.2 → 0.7.0

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: 51e2681baf728aedcec1f36235ec2c80ba340228da15d8445b64d1f520c0226d
4
- data.tar.gz: b0423051b51cce86508bc2e554365d7df66f88824124ad0157087e9b11577733
3
+ metadata.gz: 332c8451a65d8d3ef3c738e6a06d54407e62d479f6d0f015aa348c01c8c70f03
4
+ data.tar.gz: 534ae0f9dd57ee349c99fa75305370241470afb99ca0273afe98d9b206a9eb57
5
5
  SHA512:
6
- metadata.gz: b84409952c29690b3e9f731dcd4bdf15cf5b63ca494875b319d383640ebd4197f4ec3b59b0d96721d9b6ae26d4784f40a1afbb4ade69911944530f3032a7451e
7
- data.tar.gz: 786329f8de424b9a83a4eb7ac12884fa1f352f8eef62f4c65fb23b11e5561b10a2a3c204ccaf7cd4adda1988b9ca9bb2576a83df44bbbd8e88acc74a2ed6f710
6
+ metadata.gz: ce9ed85a4db89c977231290127487fde0d703ac527009173d28d0d10a1ced80a43d1febcb8cc3e4dff3b64bd80dc20c2817dd14fe301c478d3169342799f1187
7
+ data.tar.gz: 6eca9b7c49801e97d1393157c8c49a42ffafcb26bcdc103974329c2222ce3f804a496038f1cf8041836170ac251b3e9f977727f99d4bd11edad6de47931b76de
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'redis'
7
+ gem 'activesupport'
8
8
  gem 'faker'
9
9
  gem 'pry'
10
10
  gem 'rspec', '~> 3.0'
data/Gemfile.lock CHANGED
@@ -1,11 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json_schematize (0.6.0)
4
+ json_schematize (0.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ activesupport (7.0.2.4)
10
+ concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ i18n (>= 1.6, < 2)
12
+ minitest (>= 5.1)
13
+ tzinfo (~> 2.0)
9
14
  byebug (11.1.3)
10
15
  coderay (1.1.3)
11
16
  concurrent-ruby (1.1.9)
@@ -16,6 +21,7 @@ GEM
16
21
  i18n (1.10.0)
17
22
  concurrent-ruby (~> 1.0)
18
23
  method_source (1.0.0)
24
+ minitest (5.15.0)
19
25
  pry (0.13.1)
20
26
  coderay (~> 1.1)
21
27
  method_source (~> 1.0)
@@ -23,7 +29,6 @@ GEM
23
29
  byebug (~> 11.0)
24
30
  pry (~> 0.13.0)
25
31
  rake (12.3.3)
26
- redis (4.6.0)
27
32
  rspec (3.11.0)
28
33
  rspec-core (~> 3.11.0)
29
34
  rspec-expectations (~> 3.11.0)
@@ -45,17 +50,19 @@ GEM
45
50
  simplecov_json_formatter (~> 0.1)
46
51
  simplecov-html (0.12.3)
47
52
  simplecov_json_formatter (0.1.4)
53
+ tzinfo (2.0.4)
54
+ concurrent-ruby (~> 1.0)
48
55
 
49
56
  PLATFORMS
50
57
  x86_64-linux
51
58
 
52
59
  DEPENDENCIES
60
+ activesupport
53
61
  faker
54
62
  json_schematize!
55
63
  pry
56
64
  pry-byebug
57
65
  rake (~> 12.0)
58
- redis
59
66
  rspec (~> 3.0)
60
67
  rspec_junit_formatter
61
68
  simplecov
data/docker-compose.yml CHANGED
@@ -10,13 +10,6 @@ services:
10
10
  - .:/gem
11
11
  - ..:/local
12
12
  - bundle-cache:/usr/local/bundle:delegated
13
- environment:
14
- REDIS_URL: redis://redis
15
- links:
16
- - redis
17
- redis:
18
- image: redis
19
- expose:
20
- - 6379
13
+
21
14
  volumes:
22
15
  bundle-cache:
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchematize::Cache::ClassMethods
4
+ module Client
5
+
6
+ def __deserialize_keys__(key_hash_bytes)
7
+ return [{}, 0] if key_hash_bytes.nil?
8
+
9
+ min_expire = Time.now.to_i
10
+ key_hash = Marshal.load(key_hash_bytes)
11
+ keys_removed = 0
12
+ key_hash.each do |key, expire|
13
+ next if expire.to_i > min_expire
14
+
15
+ key_hash.delete(key)
16
+ keys_removed += 1
17
+ end
18
+
19
+ [key_hash, keys_removed]
20
+ rescue StandardError => e
21
+ ::Kernel.warn("Yikes!! Failed to parse. Returning empty. #{e.message}")
22
+ [{}, 0]
23
+ end
24
+
25
+ def __update_record_keeper__!(expire:, cache_key:, delete_key: false)
26
+ record_of_truth = cached_keys(with_expire: true)
27
+ if delete_key
28
+ record_of_truth.delete(cache_key)
29
+ else
30
+ record_of_truth[cache_key] = expire
31
+ end
32
+ serialized_string = Marshal.dump(record_of_truth)
33
+
34
+ cache_client.write(cache_namespace, serialized_string)
35
+ end
36
+
37
+ def __delete_record__!(key)
38
+ __update_record_keeper__!(expire: nil, cache_key: key, delete_key: true)
39
+ end
40
+
41
+ def cached_keys(with_expire: false, count_removed: false)
42
+ raw_string = cache_client.read(cache_namespace)
43
+ key_hash, keys_removed = __deserialize_keys__(raw_string)
44
+ return key_hash if with_expire
45
+ return keys_removed if count_removed
46
+
47
+ key_hash.keys
48
+ end
49
+
50
+ def cached_items(key_includes: nil)
51
+ clear_unscored_items! if rand > cache_configuration[:stochastic_cache_bust]
52
+
53
+ cached_keys.map do |key|
54
+ if key_includes
55
+ next unless key.include?(key_includes)
56
+ end
57
+
58
+ serialized_string = cache_client.read(key)
59
+ Marshal.load(serialized_string)
60
+ end.compact
61
+ end
62
+
63
+ def clear_cache!
64
+ cache_client.delete_multi(([cache_namespace] + cached_keys))
65
+ end
66
+
67
+ def clear_unscored_items!
68
+ cached_keys(count_removed: true)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchematize::Cache::ClassMethods
4
+ module Configuration
5
+ def cache_options(key: nil, cache_client: nil, cache_namespace: nil, ttl: nil, update_on_change: nil, stochastic_cache_bust: nil)
6
+ cache_configuration[:key] = key if key
7
+ cache_configuration[:ttl] = ttl if ttl
8
+ cache_configuration[:stochastic_cache_bust] = stochastic_cache_bust if stochastic_cache_bust
9
+ cache_configuration[:update_on_change] = update_on_change if update_on_change
10
+ cache_namespace = cache_configuration[:cache_namespace] = cache_namespace if cache_namespace
11
+
12
+ self.cache_client = cache_configuration[:cache_client] = cache_client if cache_client
13
+ end
14
+
15
+ def cache_namespace
16
+ cache_configuration[:cache_namespace] ||= "jss:#{self.name.downcase}"
17
+ end
18
+
19
+ def cache_namespace=(namespace)
20
+ cache_configuration[:cache_namespace] = namespace
21
+ end
22
+
23
+ def cache_configuration
24
+ @cache_configuration ||= begin
25
+ {
26
+ cache_client: JsonSchematize.configuration.cache_client,
27
+ cache_namespace: JsonSchematize.configuration.cache_namespace,
28
+ key: JsonSchematize.configuration.cache_key,
29
+ stochastic_cache_bust: JsonSchematize.configuration.cache_stochastic_bust,
30
+ ttl: JsonSchematize.configuration.cache_ttl,
31
+ update_on_change: JsonSchematize.configuration.cache_update_on_change,
32
+ }
33
+ end
34
+ end
35
+
36
+ def cache_client=(client)
37
+ cache_configuration[:cache_client] = client
38
+ end
39
+
40
+ def cache_client
41
+ cache_configuration[:cache_client].is_a?(Proc) ? cache_configuration[:cache_client].call : cache_configuration[:cache_client]
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JsonSchematize
2
4
  module Cache
3
5
  module InstanceMethods
@@ -12,16 +14,17 @@ module JsonSchematize
12
14
 
13
15
  def __update_cache_item__(with_delete: true)
14
16
  __clear_entry__! if with_delete # needs to get done first in the event the cache_key changes
15
- client = self.class.redis_client
17
+ client = self.class.cache_client
16
18
  ttl = self.class.cache_configuration[:ttl].to_i
17
19
  score = Time.now.to_i + ttl
18
- client.zadd(__cache_namespace__, score, __cache_key__)
19
- client.set(__cache_key__, Marshal.dump(self), ex: ttl)
20
+ self.class.__update_record_keeper__!(expire: score, cache_key: __cache_key__)
21
+
22
+ client.write(__cache_key__, Marshal.dump(self), expires_in: ttl)
20
23
  end
21
24
 
22
25
  def __clear_entry__!
23
- self.class.redis_client.zrem(__cache_namespace__, __cache_key__)
24
- self.class.redis_client.unlink(__cache_key__)
26
+ self.class.cache_client.delete(__cache_key__)
27
+ self.class.__delete_record__!(__cache_key__)
25
28
  end
26
29
 
27
30
  def __cache_key__
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json_schematize/cache/instance_methods"
4
- require "json_schematize/cache/class_methods"
4
+ require "json_schematize/cache/class_methods/client"
5
+ require "json_schematize/cache/class_methods/configuration"
5
6
 
6
7
  module JsonSchematize
7
8
  module Cache
8
- def self.included(base)
9
- raise StandardError, "Yikes! JsonSchematize::Cache Needs Redis to work. Include it as a gem" unless defined?(Redis)
9
+ module ClassMethods; end
10
10
 
11
+ def self.included(base)
11
12
  base.include(JsonSchematize::Cache::InstanceMethods)
12
- base.extend(JsonSchematize::Cache::ClassMethods)
13
+ base.extend(JsonSchematize::Cache::ClassMethods::Client)
14
+ base.extend(JsonSchematize::Cache::ClassMethods::Configuration)
13
15
  end
14
16
  end
15
17
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonSchematize
4
+ class Configuration
5
+ DEFAULT_ONE_MIN = 60 * 60
6
+ DEFAULT_ONE_HOUR = DEFAULT_ONE_MIN * 60
7
+ DEFAULT_ONE_DAY = DEFAULT_ONE_HOUR * 24
8
+ DEFAULT_CACHE_OPTIONS = {
9
+ cache_client: nil,
10
+ cache_key: ->(val, _custom_key) { val.hash },
11
+ cache_namespace: nil,
12
+ cache_stochastic_bust: 0.8,
13
+ cache_ttl: DEFAULT_ONE_DAY,
14
+ cache_update_on_change: true,
15
+ }
16
+
17
+ attr_accessor *DEFAULT_CACHE_OPTIONS.keys
18
+
19
+ def initialize
20
+ @cache_client = DEFAULT_CACHE_OPTIONS[:cache_client]
21
+ @cache_key = DEFAULT_CACHE_OPTIONS[:cache_key]
22
+ @cache_namespace = DEFAULT_CACHE_OPTIONS[:cache_namespace]
23
+ @cache_stochastic_bust = DEFAULT_CACHE_OPTIONS[:cache_stochastic_bust]
24
+ @cache_ttl = DEFAULT_CACHE_OPTIONS[:cache_ttl]
25
+ @cache_update_on_change = DEFAULT_CACHE_OPTIONS[:cache_update_on_change]
26
+ end
27
+
28
+ def cache_hash
29
+ DEFAULT_CACHE_OPTIONS.map do |key, value|
30
+ val = public_send(key)
31
+ [key, val]
32
+ end.to_h
33
+ end
34
+
35
+ def cache_key=(value)
36
+ if value.is_a? Proc
37
+ @key = value
38
+ return @key
39
+ end
40
+
41
+ assign = _assign_msg_("cache_key", "->(val, cusom_key) { val.hash }", "Default proc to assign cache key")
42
+ msg = "cache_key must be a proc. \n#{assign}"
43
+ raise JsonSchematize::ConfigError, msg
44
+ end
45
+
46
+ def cache_client=(client)
47
+ min_required = [:read, :write, :delete_multi, :read_multi]
48
+ min_required.each do |meth|
49
+ next if client.methods.include?(meth)
50
+
51
+ assign = _assign_msg_("cache_client", "_initialized_client_", "Preferably an ActiveSupport::Cache::Store supported client")
52
+ msg = "Passed in client does not accept minimum values. #{min_required} are required methods \n#{assign}"
53
+ raise JsonSchematize::ConfigError, msg
54
+ end
55
+
56
+
57
+ @cache_client = client
58
+ end
59
+
60
+ def cache_client
61
+ return @cache_client unless @cache_client.nil?
62
+
63
+ begin
64
+ Kernel.require 'active_support'
65
+ rescue LoadError
66
+ assign = _assign_msg_("cache_client", "ActiveSupport::Cache::MemoryStore.new", "A ActiveSupport::Cache::Store supported client")
67
+ msg = "Default client missing. Attempted to use 'active_support/cache' but not loaded. \n#{assign}"
68
+ raise JsonSchematize::ConfigError, msg
69
+ end
70
+
71
+ @cache_client = ActiveSupport::Cache::MemoryStore.new
72
+ @cache_client
73
+ end
74
+
75
+ private
76
+
77
+ def _assign_msg_(key, assignment, comment)
78
+ config = " config.#{key} = #{assignment} # #{comment}"
79
+ "\n\n# Initializer for json_schematize\n" \
80
+ "JsonSchematize.configure do |config|\n" \
81
+ "#{config}\n" \
82
+ "end\n\n"
83
+ end
84
+ end
85
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JsonSchematize
4
- VERSION = "0.6.2"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -4,12 +4,14 @@ require "json_schematize/version"
4
4
 
5
5
  require "json_schematize/base"
6
6
  require "json_schematize/boolean"
7
- require "json_schematize/generator"
7
+ require "json_schematize/configuration"
8
8
  require "json_schematize/empty_value"
9
+ require "json_schematize/generator"
9
10
  require "json_schematize/version"
10
11
 
11
12
  module JsonSchematize
12
13
  class Error < StandardError; end
14
+ class ConfigError < StandardError; end
13
15
  class FieldError < Error; end
14
16
  class InvalidField < Error; end
15
17
  class InvalidFieldByValidator < InvalidField; end
@@ -18,4 +20,22 @@ module JsonSchematize
18
20
 
19
21
  ## Customized class errors
20
22
  class UndefinedBoolean < Error; end
23
+
24
+ def self.configure
25
+ yield configuration if block_given?
26
+ end
27
+
28
+ def self.configuration
29
+ @configuration ||= JsonSchematize::Configuration.new
30
+ end
31
+
32
+ def self.configuration=(object)
33
+ raise ConfigError, "Expected configuration to be a JsonSchematize::Configuration" unless object.is_a?(JsonSchematize::Configuration)
34
+
35
+ @configuration = object
36
+ end
37
+
38
+ def self.cache_client
39
+ configuration.cache_client
40
+ end
21
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_schematize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Taylor
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-09 00:00:00.000000000 Z
11
+ date: 2022-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry-byebug
@@ -92,8 +92,10 @@ files:
92
92
  - lib/json_schematize/base.rb
93
93
  - lib/json_schematize/boolean.rb
94
94
  - lib/json_schematize/cache.rb
95
- - lib/json_schematize/cache/class_methods.rb
95
+ - lib/json_schematize/cache/class_methods/client.rb
96
+ - lib/json_schematize/cache/class_methods/configuration.rb
96
97
  - lib/json_schematize/cache/instance_methods.rb
98
+ - lib/json_schematize/configuration.rb
97
99
  - lib/json_schematize/empty_value.rb
98
100
  - lib/json_schematize/field.rb
99
101
  - lib/json_schematize/field_transformations.rb
@@ -122,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
124
  - !ruby/object:Gem::Version
123
125
  version: '0'
124
126
  requirements: []
125
- rubygems_version: 3.2.32
127
+ rubygems_version: 3.3.11
126
128
  signing_key:
127
129
  specification_version: 4
128
130
  summary: This gem gives you the ability to turn API results into a standardized schema's
@@ -1,81 +0,0 @@
1
- module JsonSchematize
2
- module Cache
3
- module ClassMethods
4
- DEFAULT_ONE_MIN = 60 * 60
5
- DEFAULT_ONE_HOUR = DEFAULT_ONE_MIN * 60
6
- DEFAULT_ONE_DAY = DEFAULT_ONE_HOUR * 24
7
- DEFAULT_URL = ENV["CACHE_LAYER_REDIS_URL"] || ENV["REDIS_URL"]
8
- DEFAULTS = {
9
- redis_url: DEFAULT_URL,
10
- ttl: DEFAULT_ONE_DAY,
11
- key: ->(val, _custom_key) { val.hash },
12
- update_on_change: true,
13
- redis_client: ->() { ::Redis.new(url: DEFAULT_URL) },
14
- stochastic_cache_bust: 0.8,
15
- }
16
-
17
- def cache_options(key: nil, redis_url: nil, redis_client: nil, cache_namespace: nil, ttl: nil, update_on_change: nil, stochastic_cache_bust: nil)
18
- cache_configuration[:key] = key if key
19
- cache_configuration[:ttl] = ttl if ttl
20
- cache_configuration[:stochastic_cache_bust] = stochastic_cache_bust if stochastic_cache_bust
21
- cache_configuration[:update_on_change] = update_on_change if update_on_change
22
- cache_namespace = cache_configuration[:cache_namespace] = cache_namespace if cache_namespace
23
-
24
- self.redis_client = cache_configuration[:redis_client] = redis_client if redis_client
25
- self.redis_url = cache_configuration[:redis_url] = redis_url if redis_url
26
- end
27
-
28
- def cache_namespace
29
- cache_configuration[:cache_namespace] ||= "jss:#{self.name.downcase}"
30
- end
31
-
32
- def cache_namespace=(namespace)
33
- cache_configuration[:cache_namespace] = namespace
34
- end
35
-
36
- def cache_configuration
37
- @cache_configuration ||= DEFAULTS.clone
38
- end
39
-
40
- def redis_client=(client)
41
- cache_configuration[:redis_client] = client
42
- end
43
-
44
- def redis_url=(url)
45
- cache_configuration[:redis_url] = url
46
- cache_configuration[:redis_client] = ::Redis.new(url: url)
47
- end
48
-
49
- def redis_client
50
- cache_configuration[:redis_client].is_a?(Proc) ? cache_configuration[:redis_client].call : cache_configuration[:redis_client]
51
- end
52
-
53
- def cached_keys
54
- max_length = Time.now.to_i + cache_configuration[:ttl].to_i + 10
55
- redis_client.zrangebyscore(cache_namespace, Time.now.to_i, "+inf")
56
- end
57
-
58
- def cached_items(key_includes: nil)
59
- clear_unscored_items! if rand > cache_configuration[:stochastic_cache_bust]
60
-
61
- cached_keys.map do |key|
62
- if key_includes
63
- next unless key.include?(key_includes)
64
- end
65
-
66
- serialized_string = redis_client.get(key)
67
- Marshal.load(serialized_string)
68
- end.compact
69
- end
70
-
71
- def clear_cache!
72
- redis_client.unlink(*cached_keys) if cached_keys.length > 0
73
- redis_client.unlink(cache_namespace)
74
- end
75
-
76
- def clear_unscored_items!
77
- redis_client.zremrangebyscore(cache_namespace, "-inf", Time.now.to_i)
78
- end
79
- end
80
- end
81
- end