adjustable_schema 0.7.2 → 0.8.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: 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: []