familia 0.10.2 → 1.0.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.pre-commit-config.yaml +1 -1
  4. data/.rubocop.yml +75 -0
  5. data/.rubocop_todo.yml +63 -0
  6. data/Gemfile +6 -1
  7. data/Gemfile.lock +47 -15
  8. data/README.md +11 -12
  9. data/VERSION.yml +4 -3
  10. data/familia.gemspec +18 -13
  11. data/lib/familia/base.rb +33 -0
  12. data/lib/familia/connection.rb +87 -0
  13. data/lib/familia/core_ext.rb +119 -124
  14. data/lib/familia/errors.rb +33 -0
  15. data/lib/familia/features/api_version.rb +19 -0
  16. data/lib/familia/features/atomic_saves.rb +8 -0
  17. data/lib/familia/features/quantizer.rb +35 -0
  18. data/lib/familia/features/safe_dump.rb +175 -0
  19. data/lib/familia/features.rb +51 -0
  20. data/lib/familia/horreum/class_methods.rb +240 -0
  21. data/lib/familia/horreum/commands.rb +59 -0
  22. data/lib/familia/horreum/relations_management.rb +141 -0
  23. data/lib/familia/horreum/serialization.rb +154 -0
  24. data/lib/familia/horreum/settings.rb +63 -0
  25. data/lib/familia/horreum/utils.rb +43 -0
  26. data/lib/familia/horreum.rb +198 -0
  27. data/lib/familia/logging.rb +249 -0
  28. data/lib/familia/redistype/commands.rb +56 -0
  29. data/lib/familia/redistype/serialization.rb +110 -0
  30. data/lib/familia/redistype.rb +185 -0
  31. data/lib/familia/settings.rb +38 -0
  32. data/lib/familia/types/hashkey.rb +108 -0
  33. data/lib/familia/types/list.rb +155 -0
  34. data/lib/familia/types/sorted_set.rb +234 -0
  35. data/lib/familia/types/string.rb +115 -0
  36. data/lib/familia/types/unsorted_set.rb +123 -0
  37. data/lib/familia/utils.rb +129 -0
  38. data/lib/familia/version.rb +25 -0
  39. data/lib/familia.rb +56 -161
  40. data/lib/redis_middleware.rb +109 -0
  41. data/try/00_familia_try.rb +5 -4
  42. data/try/10_familia_try.rb +21 -17
  43. data/try/20_redis_type_try.rb +67 -0
  44. data/try/{21_redis_object_zset_try.rb → 21_redis_type_zset_try.rb} +2 -2
  45. data/try/{22_redis_object_set_try.rb → 22_redis_type_set_try.rb} +2 -2
  46. data/try/{23_redis_object_list_try.rb → 23_redis_type_list_try.rb} +2 -2
  47. data/try/{24_redis_object_string_try.rb → 24_redis_type_string_try.rb} +6 -6
  48. data/try/{25_redis_object_hash_try.rb → 25_redis_type_hash_try.rb} +3 -3
  49. data/try/26_redis_bool_try.rb +10 -6
  50. data/try/27_redis_horreum_try.rb +40 -0
  51. data/try/30_familia_object_try.rb +21 -20
  52. data/try/35_feature_safedump_try.rb +83 -0
  53. data/try/40_customer_try.rb +140 -0
  54. data/try/41_customer_safedump_try.rb +86 -0
  55. data/try/test_helpers.rb +186 -0
  56. metadata +50 -47
  57. data/lib/familia/helpers.rb +0 -70
  58. data/lib/familia/object.rb +0 -533
  59. data/lib/familia/redisobject.rb +0 -1017
  60. data/lib/familia/test_helpers.rb +0 -40
  61. data/lib/familia/tools.rb +0 -67
  62. data/try/20_redis_object_try.rb +0 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8dbe9434bda5d5e9c9e95b094a29bfce543067013cb12b629a85f46c06a7a15
4
- data.tar.gz: b683e7b892a3d20d3d8174541bae36f1ad730928093177403f3240b307a202c8
3
+ metadata.gz: fcefc7fe4a1a64cc584d629612f752ecb1eca753ab39245217f017a03b71075e
4
+ data.tar.gz: 8a2d0313578fe9acf743537efaee95e8167eabab98474a2a821222696641b567
5
5
  SHA512:
6
- metadata.gz: 5980af9f8c2c677871bdf68823501eb6fdbfb416c723a20c7a4efe38783a1299740254f4bb85ccf50be27378c1acca10dda6a100d0b478d8a2e80e633b41b4d1
7
- data.tar.gz: 79845a5aa30366128606f784ea1187b64653cceb6466b0a459988e0ca46aa31cb8892640ed2ba332511ebcd9af5cd48d24bb48eddcbd3670ab559d2718786ee8
6
+ metadata.gz: 3f5e8755442f3766515caf445e78888fa26a1b66910bd04228d2fee24988ffa1b380ea5aeedde02a5c545e74d58fee5e273801e7c3f5cc18e873093f383da42a
7
+ data.tar.gz: 39d8c525f39c123982a150dc62e1cfd302b602086068ea7e694061bc889ab040e1765af5177e23fb9db5b408e2f4ec6f0b5d4ddf165d6ead6dce929a927a61d1
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  .DS_Store
2
2
  .bundle
3
3
  .byebug*
4
+ .prompts
4
5
  .history
5
6
  .devcontainer
6
7
  .vscode
@@ -4,7 +4,7 @@
4
4
  # Initial setup:
5
5
  #
6
6
  # 0. Install the pre-commit framework (if it isn't already on your system):
7
-
7
+ #
8
8
  # $ pip install pre-commit
9
9
  #
10
10
  # 1. Install the git hook:
data/.rubocop.yml ADDED
@@ -0,0 +1,75 @@
1
+
2
+ ##
3
+ # This is the RuboCop configuration file.
4
+ # It contains the rules and settings for the RuboCop linter.
5
+ #
6
+ # Enable/disable the cops individually. For more information,
7
+ # refer to the RuboCop documentation:
8
+ # https://docs.rubocop.org/rubocop/cops.html
9
+ #
10
+ # Running `rubocop --regenerate-todo` will update the todo file
11
+ # with the latest state of the onion (using the same options
12
+ # as those documented at the top of the todo file). This is
13
+ # useful for a gradual migration of the codebase.
14
+ #
15
+ inherit_from: .rubocop_todo.yml
16
+
17
+ require:
18
+ - rubocop-performance
19
+ - rubocop-thread_safety
20
+
21
+ AllCops:
22
+ NewCops: enable
23
+ UseCache: true
24
+ MaxFilesInCache: 100
25
+ TargetRubyVersion: 3.0
26
+ Exclude:
27
+ - 'migrate/**/*.rb'
28
+ - 'migrate/*.rb'
29
+ - 'try/**/*'
30
+ - 'try/*.rb'
31
+ - 'vendor/**/*'
32
+
33
+ Gemspec/DeprecatedAttributeAssignment:
34
+ Enabled: true
35
+
36
+ Gemspec/DevelopmentDependencies:
37
+ Enabled: true
38
+
39
+ Layout/HashAlignment:
40
+ Enabled: false
41
+
42
+ Lint/Void:
43
+ Enabled: false
44
+
45
+ Metrics/AbcSize:
46
+ Enabled: false
47
+ Max: 20
48
+
49
+ Metrics/ClassLength:
50
+ Enabled: true
51
+ Max: 200
52
+
53
+ Metrics/CyclomaticComplexity:
54
+ Enabled: false
55
+
56
+ Metrics/MethodLength:
57
+ Enabled: true
58
+ Max: 40
59
+ CountAsOne: ['method_call']
60
+
61
+ Metrics/ModuleLength:
62
+ Enabled: true
63
+ Max: 250
64
+ CountAsOne: ['method_call']
65
+
66
+ Performance/Size:
67
+ Enabled: true
68
+ Exclude:
69
+ # - lib/example.rb
70
+
71
+ Style/NegatedIfElseCondition:
72
+ Enabled: true
73
+
74
+ Naming/AsciiIdentifiers:
75
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,63 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2024-08-12 20:49:29 UTC using RuboCop version 1.65.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: EnforcedStyle, AllowedGems, Include.
11
+ # SupportedStyles: Gemfile, gems.rb, gemspec
12
+ # Include: **/*.gemspec, **/Gemfile, **/gems.rb
13
+ Gemspec/DevelopmentDependencies:
14
+ Exclude:
15
+ - 'familia.gemspec'
16
+
17
+ # Offense count: 1
18
+ # Configuration parameters: Severity, Include.
19
+ # Include: **/*.gemspec
20
+ Gemspec/RequiredRubyVersion:
21
+ Exclude:
22
+ - 'familia.gemspec'
23
+
24
+ # Offense count: 5
25
+ # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
26
+ # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
27
+ Naming/MethodParameterName:
28
+ Exclude:
29
+ - 'lib/familia/core_ext.rb'
30
+ - 'lib/familia/types/list.rb'
31
+ - 'lib/familia/types/sorted_set.rb'
32
+ - 'lib/familia/types/unsorted_set.rb'
33
+
34
+ # Offense count: 1
35
+ # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
36
+ # NamePrefix: is_, has_, have_
37
+ # ForbiddenPrefixes: is_, has_, have_
38
+ # AllowedMethods: is_a?
39
+ # MethodDefinitionMacros: define_method, define_singleton_method
40
+ Naming/PredicateName:
41
+ Exclude:
42
+ - 'spec/**/*'
43
+ - 'lib/familia/types/hashkey.rb'
44
+
45
+ # Offense count: 6
46
+ # Configuration parameters: AllowedConstants.
47
+ Style/Documentation:
48
+ Exclude:
49
+ - 'spec/**/*'
50
+ - 'test/**/*'
51
+ - 'lib/familia/errors.rb'
52
+ - 'lib/familia/types/hashkey.rb'
53
+ - 'lib/familia/types/list.rb'
54
+ - 'lib/familia/types/sorted_set.rb'
55
+ - 'lib/familia/types/string.rb'
56
+ - 'lib/familia/types/unsorted_set.rb'
57
+
58
+ # Offense count: 2
59
+ # This cop supports safe autocorrection (--autocorrect).
60
+ # Configuration parameters: MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns.
61
+ # SupportedStyles: annotated, template, unannotated
62
+ Style/FormatStringToken:
63
+ EnforcedStyle: unannotated
data/Gemfile CHANGED
@@ -1,8 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
5
7
  group :development, :test do
6
8
  gem 'pry-byebug', '~> 3.10.1', require: false
7
- gem 'tryouts', '~> 2.3', require: false
9
+ gem 'rubocop', require: false
10
+ gem 'rubocop-performance', require: false
11
+ gem 'rubocop-thread_safety', require: false
12
+ gem 'tryouts', '~> 2.4', require: false
8
13
  end
data/Gemfile.lock CHANGED
@@ -1,39 +1,67 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- familia (0.10.2)
5
- gibbler (~> 1.0.0)
6
- multi_json (~> 1.15)
4
+ familia (1.0.0.pre.rc1)
7
5
  redis (>= 4.8.1, < 6.0)
8
- storable (~> 0.10.0)
9
- uri-redis (>= 1.3.0)
6
+ uri-redis (~> 1.3)
10
7
 
11
8
  GEM
12
9
  remote: https://rubygems.org/
13
10
  specs:
14
- attic (1.0.1)
15
- rake (~> 13.0.6)
11
+ ast (2.4.2)
16
12
  byebug (11.1.3)
17
13
  coderay (1.1.3)
18
14
  connection_pool (2.4.1)
19
- gibbler (1.0.0)
20
- attic (~> 1.0)
21
- rake (~> 13.0)
15
+ drydock (0.6.9)
16
+ json (2.7.2)
17
+ language_server-protocol (3.17.0.3)
22
18
  method_source (1.1.0)
23
- multi_json (1.15.0)
19
+ parallel (1.25.1)
20
+ parser (3.3.4.0)
21
+ ast (~> 2.4.1)
22
+ racc
24
23
  pry (0.14.2)
25
24
  coderay (~> 1.1)
26
25
  method_source (~> 1.0)
27
26
  pry-byebug (3.10.1)
28
27
  byebug (~> 11.0)
29
28
  pry (>= 0.13, < 0.15)
30
- rake (13.0.6)
29
+ racc (1.8.0)
30
+ rainbow (3.1.1)
31
31
  redis (5.2.0)
32
32
  redis-client (>= 0.22.0)
33
33
  redis-client (0.22.2)
34
34
  connection_pool
35
+ regexp_parser (2.9.2)
36
+ rexml (3.3.2)
37
+ strscan
38
+ rubocop (1.65.0)
39
+ json (~> 2.3)
40
+ language_server-protocol (>= 3.17.0)
41
+ parallel (~> 1.10)
42
+ parser (>= 3.3.0.2)
43
+ rainbow (>= 2.2.2, < 4.0)
44
+ regexp_parser (>= 2.4, < 3.0)
45
+ rexml (>= 3.2.5, < 4.0)
46
+ rubocop-ast (>= 1.31.1, < 2.0)
47
+ ruby-progressbar (~> 1.7)
48
+ unicode-display_width (>= 2.4.0, < 3.0)
49
+ rubocop-ast (1.31.3)
50
+ parser (>= 3.3.1.0)
51
+ rubocop-performance (1.21.1)
52
+ rubocop (>= 1.48.1, < 2.0)
53
+ rubocop-ast (>= 1.31.1, < 2.0)
54
+ rubocop-thread_safety (0.5.1)
55
+ rubocop (>= 0.90.0)
56
+ ruby-progressbar (1.13.0)
35
57
  storable (0.10.0)
36
- tryouts (2.3.1)
58
+ strscan (3.1.0)
59
+ sysinfo (0.10.0)
60
+ drydock (< 1.0)
61
+ storable (~> 0.10)
62
+ tryouts (2.4.1)
63
+ sysinfo (~> 0.10)
64
+ unicode-display_width (2.5.0)
37
65
  uri-redis (1.3.0)
38
66
 
39
67
  PLATFORMS
@@ -42,9 +70,13 @@ PLATFORMS
42
70
  ruby
43
71
 
44
72
  DEPENDENCIES
73
+ byebug (~> 11.0)
45
74
  familia!
46
75
  pry-byebug (~> 3.10.1)
47
- tryouts (~> 2.3)
76
+ rubocop
77
+ rubocop-performance
78
+ rubocop-thread_safety
79
+ tryouts (~> 2.4)
48
80
 
49
81
  BUNDLED WITH
50
- 2.5.14
82
+ 2.5.13
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Familia - 0.10.2
1
+ # Familia - 1.0.0-rc1
2
2
 
3
3
  **Organize and store ruby objects in Redis. A Ruby ORM for Redis.**
4
4
 
@@ -6,23 +6,22 @@
6
6
 
7
7
  Get it in one of the following ways:
8
8
 
9
- * In your Gemfile: `gem 'familia', '>= 0.10.2'`
9
+ * In your Gemfile: `gem 'familia', '>= 1.0.0-rc1'`
10
10
  * Install it by hand: `gem install familia`
11
11
  * Or for development: `git clone git@github.com:delano/familia.git`
12
12
 
13
13
  ## Basic Example
14
14
 
15
15
  ```ruby
16
- class Flower < Storable
17
- include Familia
18
- index [:token, :name]
19
- field :token
20
- field :name
21
- list :owners
22
- set :tags
23
- zset :metrics
24
- hash :props
25
- string :value, :default => "GREAT!"
16
+ class Flower < Familia::Horreum
17
+ identifier :generate_id
18
+ field :token
19
+ field :name
20
+ list :owners
21
+ set :tags
22
+ zset :metrics
23
+ hashkey :props
24
+ string :counter
26
25
  end
27
26
  ```
28
27
 
data/VERSION.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
- :MAJOR: 0
3
- :MINOR: 10
4
- :PATCH: 2
2
+ :MAJOR: 1
3
+ :MINOR: 0
4
+ :PATCH: 0
5
+ :PRE: rc1
data/familia.gemspec CHANGED
@@ -1,23 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/familia/version'
4
+
1
5
  Gem::Specification.new do |spec|
2
- spec.name = "familia"
3
- spec.version = "0.10.2"
4
- spec.summary = "An ORM for Redis in Ruby."
6
+ spec.name = 'familia'
7
+ spec.version = Familia::VERSION.to_s
8
+ spec.summary = 'An ORM for Redis in Ruby.'
5
9
  spec.description = "Familia: #{spec.summary}. Organize and store ruby objects in Redis"
6
- spec.authors = ["Delano Mandelbaum"]
7
- spec.email = "gems@solutious.com"
8
- spec.homepage = "https://github.com/delano/familia"
9
- spec.license = "MIT"
10
+ spec.authors = ['Delano Mandelbaum']
11
+ spec.email = 'gems@solutious.com'
12
+ spec.homepage = 'https://github.com/delano/familia'
13
+ spec.license = 'MIT'
10
14
 
11
15
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
12
- spec.bindir = "exe"
16
+ spec.bindir = 'exe'
13
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
14
- spec.require_paths = ["lib"]
18
+ spec.require_paths = ['lib']
15
19
 
16
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.8")
20
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.8')
17
21
 
18
22
  spec.add_dependency 'redis', '>= 4.8.1', '< 6.0'
19
23
  spec.add_dependency 'uri-redis', '~> 1.3'
20
- spec.add_dependency 'gibbler', '~> 1.0.0'
21
- spec.add_dependency 'storable', '~> 0.10.0'
22
- spec.add_dependency 'multi_json', '~> 1.15'
24
+
25
+ # byebug only works with MRI
26
+ spec.add_development_dependency 'byebug', '~> 11.0' if RUBY_ENGINE == 'ruby'
27
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
28
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ module Familia
5
+ # A common module for Familia::RedisType and Familia::Horreum to include.
6
+ #
7
+ # This allows us to use a single comparison to check if a class is a
8
+ # Familia class. e.g.
9
+ #
10
+ # klass.include?(Familia::Base) # => true
11
+ # klass.ancestors.member?(Familia::Base) # => true
12
+ #
13
+ # @see Familia::Horreum
14
+ # @see Familia::RedisType
15
+ #
16
+ module Base
17
+ @features = nil
18
+ @dump_method = :to_json
19
+ @load_method = :from_json
20
+
21
+ class << self
22
+ attr_reader :features
23
+ attr_accessor :dump_method, :load_method
24
+
25
+ def add_feature(klass, methname)
26
+ @features ||= {}
27
+ Familia.ld "[#{self}] Adding feature #{klass} as #{methname}"
28
+
29
+ features[methname] = klass
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/redis_middleware'
4
+
5
+ #
6
+ module Familia
7
+ @uri = URI.parse 'redis://127.0.0.1'
8
+ @redis_clients = {}
9
+
10
+ # The Connection module provides Redis connection management for Familia.
11
+ # It allows easy setup and access to Redis clients across different URIs.
12
+ module Connection
13
+ # @return [Hash] A hash of Redis clients, keyed by server ID
14
+ attr_reader :redis_clients
15
+
16
+ # @return [URI] The default URI for Redis connections
17
+ attr_reader :uri
18
+
19
+ # @return [Boolean] Whether Redis command logging is enabled
20
+ attr_accessor :enable_redis_logging
21
+
22
+ # @return [Boolean] Whether Redis command counter is enabled
23
+ attr_accessor :enable_redis_counter
24
+
25
+ # Establishes a connection to a Redis server.
26
+ #
27
+ # @param uri [String, URI, nil] The URI of the Redis server to connect to.
28
+ # If nil, uses the default URI.
29
+ # @return [Redis] The connected Redis client
30
+ # @example
31
+ # Familia.connect('redis://localhost:6379')
32
+ def connect(uri = nil)
33
+ uri = URI.parse(uri) if uri.is_a?(String)
34
+ uri ||= Familia.uri
35
+
36
+ raise ArgumentError, 'No URI specified' unless uri
37
+
38
+ conf = uri.conf
39
+
40
+ if Familia.enable_redis_logging
41
+ RedisLogger.logger = Familia.logger
42
+ RedisClient.register(RedisLogger)
43
+ end
44
+
45
+ if Familia.enable_redis_counter
46
+ # NOTE: This middleware stays thread-safe with a mutex so it will
47
+ # be a bottleneck when enabled in multi-threaded environments.
48
+ RedisClient.register(RedisCommandCounter)
49
+ end
50
+
51
+ redis = Redis.new(conf)
52
+ @redis_clients[uri.serverid] = redis
53
+ end
54
+
55
+ # Retrieves or creates a Redis client for the given URI.
56
+ #
57
+ # @param uri [String, URI, nil] The URI of the Redis server.
58
+ # If nil, uses the default URI.
59
+ # @return [Redis] The Redis client for the specified URI
60
+ # @example
61
+ # Familia.redis('redis://localhost:6379')
62
+ def redis(uri = nil)
63
+ if uri.is_a?(Integer)
64
+ tmp = Familia.uri
65
+ tmp.db = uri
66
+ uri = tmp
67
+ elsif uri.is_a?(String)
68
+ uri &&= URI.parse uri
69
+ end
70
+ uri ||= Familia.uri
71
+ connect(uri) unless @redis_clients[uri.serverid]
72
+ @redis_clients[uri.serverid]
73
+ end
74
+
75
+ # Sets the default URI for Redis connections.
76
+ #
77
+ # @param v [String, URI] The new default URI
78
+ # @example
79
+ # Familia.uri = 'redis://localhost:6379'
80
+ def uri=(val)
81
+ @uri = val.is_a?(URI) ? v : URI.parse(val)
82
+ end
83
+
84
+ alias url uri
85
+ alias url= uri=
86
+ end
87
+ end