universalid 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +959 -186
- data/Rakefile +1 -5
- data/config/default.yml +12 -0
- data/config/example.yml +45 -0
- data/lib/universal_id/contrib/active_record/base_message_pack_type.rb +11 -0
- data/lib/universal_id/contrib/active_record/base_packer.rb +130 -0
- data/lib/universal_id/contrib/active_record/base_unpacker.rb +52 -0
- data/lib/universal_id/contrib/active_record/relation_message_pack_type.rb +16 -0
- data/lib/universal_id/contrib/active_record.rb +4 -0
- data/lib/universal_id/contrib/active_support/time_with_zone_message_pack_type.rb +14 -0
- data/lib/universal_id/contrib/active_support.rb +3 -0
- data/lib/universal_id/contrib/global_id/global_id_model.rb +24 -0
- data/lib/universal_id/contrib/global_id/global_id_uid_extension.rb +36 -0
- data/lib/universal_id/contrib/global_id/message_pack_type.rb +15 -0
- data/lib/universal_id/contrib/global_id.rb +3 -0
- data/lib/universal_id/contrib/rails.rb +6 -0
- data/lib/universal_id/contrib/signed_global_id/message_pack_type.rb +8 -0
- data/lib/universal_id/contrib/signed_global_id.rb +3 -0
- data/lib/universal_id/encoder.rb +27 -0
- data/lib/universal_id/message_pack_factory.rb +51 -0
- data/lib/universal_id/message_pack_types/ruby/composites/open_struct.rb +8 -0
- data/lib/universal_id/message_pack_types/ruby/composites/set.rb +9 -0
- data/lib/universal_id/message_pack_types/ruby/composites/struct.rb +23 -0
- data/lib/universal_id/message_pack_types/ruby/scalars/complex.rb +8 -0
- data/lib/universal_id/message_pack_types/ruby/scalars/date.rb +8 -0
- data/lib/universal_id/message_pack_types/ruby/scalars/date_time.rb +8 -0
- data/lib/universal_id/message_pack_types/ruby/scalars/range.rb +20 -0
- data/lib/universal_id/message_pack_types/ruby/scalars/rational.rb +8 -0
- data/lib/universal_id/message_pack_types/ruby/scalars/regexp.rb +15 -0
- data/lib/universal_id/message_pack_types/uri/uid/type.rb +8 -0
- data/lib/universal_id/message_pack_types.rb +24 -0
- data/lib/universal_id/prepack_database_options.rb +63 -0
- data/lib/universal_id/prepack_options.rb +74 -0
- data/lib/universal_id/prepacker.rb +28 -0
- data/lib/universal_id/refinements/array_refinement.rb +17 -0
- data/lib/universal_id/refinements/hash_refinement.rb +19 -0
- data/lib/universal_id/refinements/kernel_refinement.rb +19 -0
- data/lib/universal_id/refinements/open_struct_refinement.rb +12 -0
- data/lib/universal_id/refinements/set_refinement.rb +12 -0
- data/lib/universal_id/refinements.rb +9 -0
- data/lib/universal_id/settings.rb +82 -0
- data/lib/universal_id/version.rb +1 -1
- data/lib/universal_id.rb +25 -10
- data/lib/uri/uid.rb +95 -0
- metadata +105 -28
- data/lib/universal_id/active_model_serializer.rb +0 -53
- data/lib/universal_id/config.rb +0 -18
- data/lib/universal_id/errors.rb +0 -11
- data/lib/universal_id/portable.rb +0 -24
- data/lib/universal_id/portable_hash.rb +0 -85
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UniversalID::PrepackDatabaseOptions
|
4
|
+
def initialize(settings)
|
5
|
+
@settings = settings
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_h
|
9
|
+
@settings.to_h
|
10
|
+
end
|
11
|
+
|
12
|
+
def include_keys?
|
13
|
+
!!@settings.include_keys
|
14
|
+
end
|
15
|
+
|
16
|
+
def exclude_keys?
|
17
|
+
!include_keys?
|
18
|
+
end
|
19
|
+
|
20
|
+
def include_timestamps?
|
21
|
+
!!@settings.include_timestamps
|
22
|
+
end
|
23
|
+
|
24
|
+
def exclude_timestamps?
|
25
|
+
!include_timestamps?
|
26
|
+
end
|
27
|
+
|
28
|
+
def include_unsaved_changes?
|
29
|
+
!!@settings.include_unsaved_changes
|
30
|
+
end
|
31
|
+
|
32
|
+
def exclude_unsaved_changes?
|
33
|
+
!include_unsaved_changes?
|
34
|
+
end
|
35
|
+
|
36
|
+
def descendant_depth
|
37
|
+
@settings.descendant_depth ||= 0
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_writer :current_depth
|
41
|
+
|
42
|
+
def current_depth
|
43
|
+
@settings.current_depth ||= 0
|
44
|
+
end
|
45
|
+
|
46
|
+
def increment_current_depth!
|
47
|
+
@settings.current_depth ||= 0
|
48
|
+
@settings.current_depth = @settings.current_depth += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def decrement_current_depth!
|
52
|
+
@settings.current_depth ||= 0
|
53
|
+
@settings.current_depth = @settings.current_depth -= 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def include_descendants?
|
57
|
+
!!@settings.include_descendants
|
58
|
+
end
|
59
|
+
|
60
|
+
def exclude_descentants?
|
61
|
+
!include_descendants?
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "prepack_database_options"
|
4
|
+
|
5
|
+
class UniversalID::PrepackOptions
|
6
|
+
attr_reader :excludes, :includes, :database_options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
options ||= {}
|
10
|
+
@settings = UniversalID::Settings.build(**options).prepack
|
11
|
+
@database_options = UniversalID::PrepackDatabaseOptions.new(@settings.database)
|
12
|
+
@references = Set.new
|
13
|
+
@excludes ||= @settings.exclude.to_h { |key| [key.to_s, true] }
|
14
|
+
@includes ||= @settings.include.to_h { |key| [key.to_s, true] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_h
|
18
|
+
@settings.to_h
|
19
|
+
end
|
20
|
+
|
21
|
+
def prevent_self_reference!(object)
|
22
|
+
raise UniversalID::Prepacker::CircularReferenceError if @references.include?(object.object_id)
|
23
|
+
@references << object.object_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def include_blank?
|
27
|
+
!!@settings.include_blank
|
28
|
+
end
|
29
|
+
|
30
|
+
def exclude_blank?
|
31
|
+
!include_blank?
|
32
|
+
end
|
33
|
+
|
34
|
+
def keep_key?(key)
|
35
|
+
return false if excludes[key.to_s]
|
36
|
+
includes.none? || includes[key.to_s]
|
37
|
+
end
|
38
|
+
|
39
|
+
def reject_key?(key)
|
40
|
+
excludes[key.to_s]
|
41
|
+
end
|
42
|
+
|
43
|
+
def keep_value?(value)
|
44
|
+
include_blank? || present?(value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def reject_value?(value)
|
48
|
+
!keep_value?(value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def keep_keypair?(key, value)
|
52
|
+
keep_key?(key) && keep_value?(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def reject_keypair?(key, value)
|
56
|
+
reject_key?(key) || reject_value?(value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def blank?(value)
|
60
|
+
return true if value.nil?
|
61
|
+
return false if !!value == value # booleans
|
62
|
+
|
63
|
+
result = false
|
64
|
+
result ||= value.empty? if value.respond_to?(:empty?)
|
65
|
+
result ||= value.blank? if value.respond_to?(:blank?)
|
66
|
+
result ||= value.strip.empty? if value.is_a?(String)
|
67
|
+
result ||= value.compact.empty? if value.is_a?(Array) || value.is_a?(Hash)
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
71
|
+
def present?(value)
|
72
|
+
!blank?(value)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "refinements"
|
4
|
+
|
5
|
+
class UniversalID::Prepacker
|
6
|
+
using UniversalID::Refinements::KernelRefinement
|
7
|
+
using UniversalID::Refinements::ArrayRefinement
|
8
|
+
using UniversalID::Refinements::HashRefinement
|
9
|
+
using UniversalID::Refinements::SetRefinement
|
10
|
+
using UniversalID::Refinements::OpenStructRefinement
|
11
|
+
|
12
|
+
class CircularReferenceError < StandardError
|
13
|
+
def initialize(message = "Prepacking not supported on self referencing objects!")
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def prepack(object, options = {})
|
20
|
+
options = UniversalID::PrepackOptions.new(options) unless options.is_a?(UniversalID::PrepackOptions)
|
21
|
+
|
22
|
+
return object.prepack(options) if object.respond_to?(:prepack)
|
23
|
+
|
24
|
+
object.instance_variable_set(:@_uid_prepack_options, options) unless object.frozen?
|
25
|
+
object
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UniversalID::Refinements::ArrayRefinement
|
4
|
+
refine Array do
|
5
|
+
def prepack(options)
|
6
|
+
options.prevent_self_reference! self
|
7
|
+
|
8
|
+
copy = each_with_object([]) do |val, memo|
|
9
|
+
val = UniversalID::Prepacker.prepack(val, options)
|
10
|
+
memo << val if options.keep_value?(val)
|
11
|
+
end
|
12
|
+
|
13
|
+
copy.compact! if options.exclude_blank?
|
14
|
+
copy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UniversalID::Refinements::HashRefinement
|
4
|
+
refine Hash do
|
5
|
+
using UniversalID::Refinements::ArrayRefinement
|
6
|
+
|
7
|
+
def prepack(options)
|
8
|
+
options.prevent_self_reference! self
|
9
|
+
|
10
|
+
copy = each_with_object({}) do |(key, val), memo|
|
11
|
+
next unless options.keep_keypair?(key, val)
|
12
|
+
memo[key] = UniversalID::Prepacker.prepack(val, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
copy.compact! if options.exclude_blank?
|
16
|
+
copy
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UniversalID::Refinements::KernelRefinement
|
4
|
+
refine Kernel do
|
5
|
+
# Finds a constant by name, starting at the root namespace (i.e. ::Object)
|
6
|
+
def const_find(name)
|
7
|
+
return nil unless name.is_a?(String)
|
8
|
+
names = name.split("::")
|
9
|
+
constant = Object
|
10
|
+
|
11
|
+
while names.any?
|
12
|
+
value = names.shift
|
13
|
+
constant = constant.const_get(value) if constant.const_defined?(value)
|
14
|
+
end
|
15
|
+
|
16
|
+
(constant.name == name) ? constant : nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UniversalID::Refinements::OpenStructRefinement
|
4
|
+
refine OpenStruct do
|
5
|
+
using UniversalID::Refinements::HashRefinement
|
6
|
+
|
7
|
+
def prepack(options)
|
8
|
+
options.prevent_self_reference! self
|
9
|
+
OpenStruct.new to_h.prepack(options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UniversalID::Refinements::SetRefinement
|
4
|
+
refine Set do
|
5
|
+
using UniversalID::Refinements::ArrayRefinement
|
6
|
+
|
7
|
+
def prepack(options)
|
8
|
+
options.prevent_self_reference! self
|
9
|
+
Set.new to_a.prepack(options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UniversalID::Refinements; end
|
4
|
+
|
5
|
+
require_relative "refinements/kernel_refinement"
|
6
|
+
require_relative "refinements/array_refinement"
|
7
|
+
require_relative "refinements/hash_refinement"
|
8
|
+
require_relative "refinements/set_refinement"
|
9
|
+
require_relative "refinements/open_struct_refinement"
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "monitor"
|
4
|
+
require "singleton"
|
5
|
+
require "config"
|
6
|
+
|
7
|
+
class UniversalID::Settings
|
8
|
+
include MonitorMixin
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
DEFAULT_FILE_PATH = File.expand_path("../../config/default.yml", __dir__)
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def build(**options)
|
15
|
+
instance.default_copy.tap do |settings|
|
16
|
+
options.each { |key, val| assign key, val, to: settings }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def register(...)
|
21
|
+
instance.register(...)
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
instance[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def assign(key, value, to:)
|
31
|
+
return if value.nil?
|
32
|
+
|
33
|
+
case {key.to_sym => value}
|
34
|
+
in prepack: prepack then prepack.each { |k, v| assign k, v, to: to }
|
35
|
+
in exclude: exclude then to.prepack.exclude = exclude
|
36
|
+
in include: inc then to.prepack.include = inc
|
37
|
+
in include_blank: include_blank then to.prepack.include_blank = !!include_blank
|
38
|
+
in database: database then database.each { |k, v| assign k, v, to: to }
|
39
|
+
in include_keys: include_keys then to.prepack.database.include_keys = !!include_keys
|
40
|
+
in include_timestamps: include_timestamps then to.prepack.database.include_timestamps = !!include_timestamps
|
41
|
+
in include_unsaved_changes: include_unsaved_changes then to.prepack.database.include_unsaved_changes = !!include_unsaved_changes
|
42
|
+
in include_descendants: include_descendants then to.prepack.database.include_descendants = !!include_descendants
|
43
|
+
in descendant_depth: descendant_depth then to.prepack.database.descendant_depth = descendant_depth
|
44
|
+
else # ignore key
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def register(key, options = {})
|
50
|
+
key = key.to_s.strip.downcase.to_sym
|
51
|
+
synchronize do
|
52
|
+
raise ArgumentError, "Already registered! key: #{key}" if registry.key? key
|
53
|
+
config = case options
|
54
|
+
when String then Config.load_files(options)
|
55
|
+
when Hash then Config::Options.new(options)
|
56
|
+
when Config::Options then options
|
57
|
+
else raise ArgumentError, "Invalid options! Must be a String, Hash, or Config::Options."
|
58
|
+
end
|
59
|
+
|
60
|
+
config = self.class.build(**config) unless key == :default
|
61
|
+
registry[key] = config
|
62
|
+
self.class.define_method(key) { config }
|
63
|
+
self.class.define_method("#{key}_copy") { Marshal.load Marshal.dump(config) }
|
64
|
+
self.class.define_singleton_method(key) { instance.public_send key }
|
65
|
+
[key, config]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def [](key)
|
70
|
+
registry[key.to_sym]
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
attr_reader :registry
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
super
|
79
|
+
@registry = {}
|
80
|
+
register :default, DEFAULT_FILE_PATH
|
81
|
+
end
|
82
|
+
end
|
data/lib/universal_id/version.rb
CHANGED
data/lib/universal_id.rb
CHANGED
@@ -1,13 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "
|
5
|
-
require "
|
6
|
-
require "
|
7
|
-
|
3
|
+
require "date"
|
4
|
+
require "forwardable"
|
5
|
+
require "ostruct"
|
6
|
+
require "uri"
|
7
|
+
|
8
8
|
require_relative "universal_id/version"
|
9
|
-
require_relative "universal_id/
|
10
|
-
require_relative "universal_id/
|
11
|
-
require_relative "
|
12
|
-
require_relative "universal_id/
|
13
|
-
require_relative "universal_id/
|
9
|
+
require_relative "universal_id/settings"
|
10
|
+
require_relative "universal_id/encoder"
|
11
|
+
require_relative "uri/uid"
|
12
|
+
require_relative "universal_id/prepacker"
|
13
|
+
require_relative "universal_id/prepack_options"
|
14
|
+
require_relative "universal_id/message_pack_factory"
|
15
|
+
|
16
|
+
UniversalID::Settings.instance # initialize settings
|
17
|
+
|
18
|
+
module UniversalID
|
19
|
+
module Contrib; end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_writer :logger
|
23
|
+
|
24
|
+
def logger
|
25
|
+
@logger ||= defined?(Rails) ? Rails.logger : Logger.new(File::NULL)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/uri/uid.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
unless defined?(::URI::UID) || ::URI.scheme_list.include?("UID")
|
4
|
+
|
5
|
+
module URI
|
6
|
+
class UID < ::URI::Generic
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
SCHEME = "uid"
|
10
|
+
HOST = "universal-id"
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def parse(value)
|
14
|
+
components = ::URI.split(value.to_s)
|
15
|
+
new(*components)
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_string(payload)
|
19
|
+
"#{SCHEME}://#{HOST}/#{payload}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def build(object, options = {})
|
23
|
+
path = "/#{UniversalID::Encoder.encode(object, options)}"
|
24
|
+
parse "#{SCHEME}://#{HOST}#{path}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Creates a new URI::UID with the given URI components.
|
28
|
+
# SEE: https://ruby-doc.org/3.2.2/stdlibs/uri/URI/Generic.html#method-c-new
|
29
|
+
#
|
30
|
+
# @param scheme [String] the scheme component.
|
31
|
+
# @param userinfo [String] the userinfo component.
|
32
|
+
# @param host [String] the host component.
|
33
|
+
# @param port [Integer] the port component.
|
34
|
+
# @param registry [String] the registry component.
|
35
|
+
# @param path [String] the path component.
|
36
|
+
# @param opaque [String] the opaque component.
|
37
|
+
# @param query [String] the query component.
|
38
|
+
# @param fragment [String] the fragment component.
|
39
|
+
# @param parser [URI::Parser] the parser to use for the URI, defaults to DEFAULT_PARSER.
|
40
|
+
# @param arg_check [Boolean] whether to check arguments, defaults to false.
|
41
|
+
# @return [URI::UID] the new URI::UID instance.
|
42
|
+
# # @raise [URI::InvalidURIError] if the URI is malformed.
|
43
|
+
# @raise [ArgumentError] if the number of arguments is incorrect or an argument is of the wrong type.
|
44
|
+
# @raise [TypeError] if an argument is not of the expected type.
|
45
|
+
# @raise [URI::InvalidComponentError] if a component of the URI is not valid.
|
46
|
+
# @raise [URI::BadURIError] if the URI is in a bad or unexpected state.
|
47
|
+
def new(...)
|
48
|
+
super.tap do |uri|
|
49
|
+
if uri.invalid?
|
50
|
+
raise ::URI::InvalidComponentError, "Scheme must be `#{SCHEME}`" if uri.scheme != SCHEME
|
51
|
+
raise ::URI::InvalidComponentError, "Host must be `#{HOST}`" if uri.host != HOST
|
52
|
+
raise ::URI::InvalidComponentError, "Unable to parse `payload` from the path component!" if uri.payload.strip.empty?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def payload(truncate: false)
|
59
|
+
(truncate && path.length > 80) ? "#{path[1..77]}..." : path[1..]
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid?
|
63
|
+
case self
|
64
|
+
in scheme: SCHEME, host: HOST, path: p if p.size >= 8 then return true
|
65
|
+
else false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def invalid?
|
70
|
+
!valid?
|
71
|
+
end
|
72
|
+
|
73
|
+
def decode
|
74
|
+
UniversalID::Encoder.decode(payload) if valid?
|
75
|
+
end
|
76
|
+
|
77
|
+
def deconstruct_keys(_keys)
|
78
|
+
{scheme: scheme, host: host, path: path}
|
79
|
+
end
|
80
|
+
|
81
|
+
def inspect
|
82
|
+
"#<URI::UID scheme=#{scheme}, host=#{host}, payload=#{payload truncate: true}>"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Register the URI scheme
|
87
|
+
if ::URI.respond_to? :register_scheme
|
88
|
+
::URI.register_scheme "UID", UID unless ::URI.scheme_list.include?("UID")
|
89
|
+
else
|
90
|
+
# shenanigans to support Ruby 3.0.X
|
91
|
+
::URI::UID = UID unless defined?(::URI::UID)
|
92
|
+
::URI.scheme_list["UID"] = UID
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|