adjustable_schema 0.7.2 → 0.8.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f44c8a85801250e7f4d0e26af1984a77f7e59d0d0f31f416e8d55343fdefb94a
4
- data.tar.gz: fd68da65c3953097520bd12263924482d11330b7862c5bb7cf4aeffef972ecc8
3
+ metadata.gz: 7e36fef6757e9e0803ad940f90a425ea0b25870c0720b0d338ed14970a35e339
4
+ data.tar.gz: a50db598919a729c33f607f107b1f78145d3fe262e00d0b7899dacb473ebc194
5
5
  SHA512:
6
- metadata.gz: 05bc3d492e1794d4549668cf853b07fc824b5285fb6062287f11875ba8d408f1f2c1fc9fcaa26becd797ee04e9ed1c9ed997a4a998eb21dc70ba77486a1725e3
7
- data.tar.gz: 44e8c6b9fef8f06d4bedd14213ae08a62e425825fe3a30c6843117c1d1b2e4cabbd66ec00e2bef5b5fb9ab1bd7e4e3696e3e784b24a62832bab66ee2d54d6b4b
6
+ metadata.gz: 631771aa7ea4295ba2d886ab24a1e102b1ab50b9d3631ff467a3f46fd6f48a5bcd1f4ff2af62523510cc4c5d361852ef71dd183ca5846d20cf3a939ba25864f8
7
+ data.tar.gz: 57cd60293cb11377429fb2f808115301bb84f3a9c71372c7e0e5040bc8441e3ca62b244906d96785f1a34845c9542a1617107d7887dd01b9481b2b658ecae1d5
data/CHANGELOG.md CHANGED
@@ -0,0 +1,108 @@
1
+ ## [0.8.0] — 2024-11-08
2
+
3
+ ### Changed
4
+
5
+ - Renamed checks for related records:
6
+ `<associat>ful` form is now used instead of a passive one (`<associat>ed`) to check for related records’ presence.
7
+ - `.<associat>ful` — scope records having associated ones.
8
+ - `#<associat>ful?` — are there any records associated?
9
+ - Naming: improved passive forms for words ending with `or`/`ant`/`ion`/`ment`/`ing`.
10
+
11
+ ### Added
12
+
13
+ - Checks for related records’ presence on roleless recursive associations:
14
+ - `.<associat>ful` —
15
+ records having associated ones;
16
+ - `.<association>less` —
17
+ records not having associated ones;
18
+ - `#<associat>ful?` —
19
+ if there are records associated;
20
+ - `#<association>less?` —
21
+ if there are no records associated;
22
+ - `#intermediate?` —
23
+ whether is only one child record associated (_Is the node just a link between two other nodes like?_);
24
+ - `#branching?` —
25
+ whether are several child records associated.
26
+
27
+ ### Fixed
28
+
29
+ - Naming: passive form for `author`.
30
+
31
+
32
+ ## [0.7.2] — 2024-04-02
33
+
34
+ ### Fixed
35
+
36
+ - `roleless` scope used to generate wrong queries.
37
+
38
+
39
+ ## [0.7.1] — 2024-03-31
40
+
41
+ ### Fixed
42
+
43
+ - DB constraints:
44
+ - `roles.name` is `NOT NULL`,
45
+ - `UNIQUE` constraints should treat `NULLS` as `NOT DISTINCT`.
46
+ - Roleless recursive associations used to fail on `joins`.
47
+
48
+
49
+ ## [0.7.0] — 2024-02-25
50
+
51
+ ### Changed
52
+
53
+ - Naming: improved passive forms a bit.
54
+ - Configuration: renamed `self_related` to `self`.
55
+
56
+ ### Added
57
+
58
+ - Checks for related records’ presence:
59
+ - `.<associat>ed` —
60
+ records having associated ones;
61
+ - `.<association>less` —
62
+ records not having associated ones;
63
+ - `#<associat>ed?` —
64
+ if there are records associated;
65
+ - `#<association>less?` —
66
+ if there are no records associated.
67
+ - Documentation: self-targeted relationships in README.
68
+
69
+ ### Fixed
70
+
71
+ - Documentation: examples in the README.
72
+
73
+
74
+ ## [0.6.0] — 2024-02-20
75
+
76
+ ### Changed
77
+
78
+ - Destroy orphaned relationships of an object on destroy.
79
+ - Symbolize configurable names used for associations, methods, etc.
80
+ - Raise `ArgumentError` for unknown names passed to the API.
81
+
82
+ ### Added
83
+
84
+ - `Relationship[]` to filter relationships by related objects/classes.
85
+ - `Role[]` accepts `Hash`-like parameters to filter roles by relationships.
86
+ - Methods for related records:
87
+ - `related?` to check for related objects,
88
+ - `related` to fetch them,
89
+ - and the basic `relationships`.
90
+ - Recursive methods for related records:
91
+ - flat `ancestors` & `descendants` with distance,
92
+ - based on `recursive` association scope.
93
+ - `roleless` scope for related records without a role.
94
+ - A dedicated association for roleless children.
95
+
96
+ ### Fixed
97
+
98
+ - Faulty scopes in role-based relationship associations.
99
+ - Naming for namespaced models, e.g., in Rails Engines.
100
+
101
+
102
+ ## [0.5.0] — 2023-12-29
103
+
104
+ Refactored from [Rails Dynamic Associations](
105
+ https://github.com/Alexander-Senko/rails_dynamic_associations
106
+ ).
107
+
108
+ Some experimental features are missing and can be found in the `api` branch.
data/README.md CHANGED
@@ -75,7 +75,7 @@ It includes `User` by default.
75
75
 
76
76
  ##### Self-referencing models
77
77
 
78
- You may want to set up self-targeted relationships:
78
+ You may want to set up recursive relationships:
79
79
 
80
80
  ``` ruby
81
81
  AdjustableSchema::Relationship.seed! Person, roles: %w[friend]
@@ -100,7 +100,7 @@ AdjustableSchema::Engine.configure do
100
100
  end
101
101
  ```
102
102
 
103
- Thus, for the self-referenced `Event`s, you'll get:
103
+ Thus, for hierarchical `Event`s, you'll get:
104
104
 
105
105
  ``` ruby
106
106
  event.causes
@@ -15,7 +15,7 @@ module AdjustableSchema
15
15
  where association => object
16
16
  when Class
17
17
  where "#{association}_type" => object.ancestors
18
- .select { _1 <= object.base_class }
18
+ .grep(..object.base_class)
19
19
  .map(&:name)
20
20
  when ::ActiveRecord::Relation
21
21
  send(method, object.klass)
@@ -100,7 +100,7 @@ module AdjustableSchema
100
100
  end
101
101
  end
102
102
  in [ Class => source ]
103
- seed! source, source, roles: # self-related
103
+ seed! source, source, roles: # recursive
104
104
  end
105
105
  end
106
106
  end
@@ -46,7 +46,7 @@ module AdjustableSchema
46
46
  Config.association_directions
47
47
  .map { relationship.send _1 } # both objects
48
48
  .without(self) # the related one
49
- .first or self # may be self-related
49
+ .first or self # may be recursive
50
50
  end
51
51
  .uniq
52
52
  end
@@ -28,7 +28,7 @@ class CreateAdjustableSchemaRelationshipTables < ActiveRecord::Migration[7.1]
28
28
  # One can use `ADD CONSTRAINT … UNIQUE NULLS NOT DISTINCT (…)` instead
29
29
  t.index columns,
30
30
  unique: true, where: 'role_id IS NOT NULL', name: :index_adjustable_schema_relationships_uniqueness_with_role
31
- t.index columns.excluding(:role_id),
31
+ t.index columns.without(:role_id),
32
32
  unique: true, where: 'role_id IS NULL', name: :index_adjustable_schema_relationships_uniqueness_without_role
33
33
  }
34
34
  end
@@ -10,21 +10,32 @@ module AdjustableSchema
10
10
  refine String do
11
11
  def passivize
12
12
  self
13
- .sub(/(author)$/, '\\2ed')
14
- .sub(/(e*|ed|ing|[eo]r|ant|(t)ion)$/, '\\2ed')
13
+ .presence
14
+ &.sub(/((:?[aeiou]+[^aeiou]+){2,})(?:or|ant|ion|e?ment)$/, '\1ed')
15
+ &.sub(/((:?[aeiou]+[^aeiou]+){1,})(?:ing)$/, '\1ed')
16
+ &.sub(/(?:e*|ed|er)$/, '\1ed')
17
+ .to_s
15
18
  end
16
19
  end
17
20
  end
18
21
 
19
22
  using Inflections
20
23
 
21
- memoize def name
22
- (role ? name_with_role : name_without_role)
24
+ memoize def name name = object_name
25
+ name
23
26
  .to_s
24
27
  .tableize
25
28
  .to_sym
26
29
  end
27
30
 
31
+ def object_name
32
+ if role
33
+ name_with_role
34
+ else
35
+ name_without_role
36
+ end
37
+ end
38
+
28
39
  memoize def target_name
29
40
  target.model_name.unnamespaced
30
41
  .split('::')
@@ -51,17 +62,20 @@ module AdjustableSchema
51
62
  end
52
63
  end
53
64
 
54
- memoize def name_without_role
65
+ def name_without_role
55
66
  if recursive?
56
67
  Config.association_directions
57
68
  .self[direction]
69
+ .to_s
58
70
  else
59
71
  target_name
60
72
  end
61
73
  end
62
74
 
63
- def name_for_any = :"#{name.to_s.singularize.passivize}"
64
- def name_for_none = :"#{name.to_s.singularize}less"
75
+ def roleless_name = name(target_name)
76
+
77
+ def name_for_any (name = object_name) = :"#{name}ful"
78
+ def name_for_none(name = object_name) = :"#{name}less"
65
79
  end
66
80
  end
67
81
  end
@@ -24,8 +24,8 @@ module AdjustableSchema
24
24
  unless role
25
25
  # HACK: using `try` to overcome a Rails bug
26
26
  # (see https://github.com/rails/rails/issues/40109)
27
- has_many target_name.tableize.to_sym, -> { try :roleless }, **options if
28
- recursive?
27
+ has_many roleless_name, -> { try :roleless }, **options if
28
+ child?
29
29
 
30
30
  define_role_methods
31
31
  end
@@ -33,6 +33,12 @@ module AdjustableSchema
33
33
  end
34
34
 
35
35
  def recursive? = target == owner
36
+ def roleless? = !role
37
+ def source? = direction == :source
38
+ def target? = direction == :target
39
+ def child? = (recursive? and source?)
40
+ def parent? = (recursive? and target?)
41
+ def hierarchy? = (child? and roleless?)
36
42
 
37
43
  private
38
44
 
@@ -46,22 +52,36 @@ module AdjustableSchema
46
52
  end
47
53
 
48
54
  def define_scopes
49
- name = relationships_name
55
+ name = relationships_name
56
+ roleless_name = self.roleless_name
50
57
 
51
58
  {
52
59
  name_for_any => -> { where.associated name },
53
60
  name_for_none => -> { where.missing name },
61
+
62
+ **({
63
+ name_for_any( target_name) => -> { where.associated roleless_name },
64
+ name_for_none(target_name) => -> { where.missing roleless_name },
65
+ } if hierarchy?),
54
66
  }
55
67
  .reject { owner.singleton_class.method_defined? _1 }
56
68
  .each { owner.scope _1, _2 }
57
69
  end
58
70
 
59
71
  def define_methods
60
- name = self.name
72
+ name = self.name
73
+ roleless_name = self.roleless_name
61
74
 
62
75
  {
63
76
  name_for_any => -> { send(name).any? },
64
77
  name_for_none => -> { send(name).none? },
78
+
79
+ **(hierarchy? ? {
80
+ name_for_any( target_name) => -> { send(roleless_name).any? },
81
+ name_for_none(target_name) => -> { send(roleless_name).none? },
82
+ intermediate: -> { send(roleless_name).one? },
83
+ branching: -> { send(roleless_name).many? },
84
+ } : {}),
65
85
  }
66
86
  .transform_keys {"#{_1}?" }
67
87
  .reject { owner.method_defined? _1 }
@@ -11,7 +11,7 @@ module AdjustableSchema
11
11
  config(:shortcut).tap do |shortcuts|
12
12
  def shortcuts.opposite to: nil
13
13
  if to
14
- values.reject { _1 == to }.sole
14
+ values.grep_v(to).sole
15
15
  else
16
16
  transform_values { opposite to: _1 }
17
17
  end
@@ -28,7 +28,7 @@ module AdjustableSchema
28
28
  end
29
29
 
30
30
  def opposite to:
31
- reject { _1 == to }.sole
31
+ grep_v(to).sole
32
32
  end
33
33
 
34
34
  private
@@ -1,3 +1,3 @@
1
1
  module AdjustableSchema
2
- VERSION = '0.7.2'
2
+ VERSION = '0.8.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adjustable_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Senko
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-04-02 00:00:00.000000000 Z
10
+ date: 2024-11-08 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -111,8 +110,7 @@ licenses:
111
110
  metadata:
112
111
  homepage_uri: https://github.com/Alexander-Senko/adjustable_schema
113
112
  source_code_uri: https://github.com/Alexander-Senko/adjustable_schema
114
- changelog_uri: https://github.com/Alexander-Senko/adjustable_schema/blob/v0.7.2/CHANGELOG.md
115
- post_install_message:
113
+ changelog_uri: https://github.com/Alexander-Senko/adjustable_schema/blob/v0.8.0/CHANGELOG.md
116
114
  rdoc_options: []
117
115
  require_paths:
118
116
  - lib
@@ -127,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
125
  - !ruby/object:Gem::Version
128
126
  version: '0'
129
127
  requirements: []
130
- rubygems_version: 3.5.6
131
- signing_key:
128
+ rubygems_version: 3.6.0.dev
132
129
  specification_version: 4
133
130
  summary: Adjustable data schemas for Rails
134
131
  test_files: []