anchormodel 0.2.6 → 0.3.1

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.
data/doc/js/full_list.js CHANGED
@@ -62,25 +62,8 @@ function enableToggles() {
62
62
  evt.stopPropagation();
63
63
  evt.preventDefault();
64
64
  $(this).parent().parent().toggleClass('collapsed');
65
- $(this).attr('aria-expanded', function (i, attr) {
66
- return attr == 'true' ? 'false' : 'true'
67
- });
68
65
  highlight();
69
66
  });
70
-
71
- // navigation of nested classes using keyboard
72
- $('#full_list a.toggle').on('keypress',function(evt) {
73
- // enter key is pressed
74
- if (evt.which == 13) {
75
- evt.stopPropagation();
76
- evt.preventDefault();
77
- $(this).parent().parent().toggleClass('collapsed');
78
- $(this).attr('aria-expanded', function (i, attr) {
79
- return attr == 'true' ? 'false' : 'true'
80
- });
81
- highlight();
82
- }
83
- });
84
67
  }
85
68
 
86
69
  function populateSearchCache() {
@@ -108,7 +91,7 @@ function enableSearch() {
108
91
  }
109
92
  });
110
93
 
111
- $('#full_list').after("<div id='noresults' role='status' style='display: none'></div>");
94
+ $('#full_list').after("<div id='noresults' style='display:none'></div>");
112
95
  }
113
96
 
114
97
  function ignoredKeyPress(event) {
@@ -171,14 +154,11 @@ function partialSearch(searchString, offset) {
171
154
  function searchDone() {
172
155
  searchTimeout = null;
173
156
  highlight();
174
- var found = $('#full_list li:visible').size();
175
- if (found === 0) {
176
- $('#noresults').text('No results were found.');
157
+ if ($('#full_list li:visible').size() === 0) {
158
+ $('#noresults').text('No results were found.').hide().fadeIn();
177
159
  } else {
178
- // This is read out to screen readers
179
- $('#noresults').text('There are ' + found + ' results.');
160
+ $('#noresults').text('').hide();
180
161
  }
181
- $('#noresults').show();
182
162
  $('#content').removeClass('insearch');
183
163
  }
184
164
 
@@ -208,12 +188,6 @@ function expandTo(path) {
208
188
  $target.addClass('clicked');
209
189
  $target.removeClass('collapsed');
210
190
  $target.parentsUntil('#full_list', 'li').removeClass('collapsed');
211
-
212
- $target.find('a.toggle').attr('aria-expanded', 'true')
213
- $target.parentsUntil('#full_list', 'li').each(function(i, el) {
214
- $(el).find('> div > a.toggle').attr('aria-expanded', 'true');
215
- });
216
-
217
191
  if($target[0]) {
218
192
  window.scrollTo(window.scrollX, $target.offset().top - 250);
219
193
  highlight();
data/doc/method_list.html CHANGED
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html >
2
+ <html>
3
3
  <head>
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
5
  <meta charset="utf-8" />
@@ -38,10 +38,7 @@
38
38
 
39
39
  </div>
40
40
 
41
- <div id="search">
42
- <label for="search-class">Search:</label>
43
- <input id="search-class" type="text" />
44
- </div>
41
+ <div id="search">Search: <input type="text" /></div>
45
42
  </div>
46
43
 
47
44
  <ul id="full_list" class="method">
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Documentation by YARD 0.9.37
9
+ &mdash; Documentation by YARD 0.9.28
10
10
 
11
11
  </title>
12
12
 
@@ -100,9 +100,9 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Thu Aug 7 15:55:29 2025 by
103
+ Generated on Wed May 13 11:46:10 2026 by
104
104
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
- 0.9.37 (ruby-3.3.5).
105
+ 0.9.28 (ruby-3.3.5).
106
106
  </div>
107
107
 
108
108
  </div>
@@ -20,6 +20,23 @@ class Anchormodel::ActiveModelTypeValueSingle < ActiveModel::Type::Value
20
20
 
21
21
  # This converts an Anchormodel instance to string for DB
22
22
  def serialize(value)
23
+ return value.map { |v| serialize_scalar(v) } if value.is_a?(Array)
24
+ serialize_scalar(value)
25
+ end
26
+
27
+ def serializable?(value)
28
+ return value.all? { |v| scalar_serializable?(v) } if value.is_a?(Array)
29
+ scalar_serializable?(value)
30
+ end
31
+
32
+ def changed_in_place?(raw_old_value, value)
33
+ old_value = deserialize(raw_old_value)
34
+ old_value != value
35
+ end
36
+
37
+ private
38
+
39
+ def serialize_scalar(value)
23
40
  value = value.presence
24
41
  return case value
25
42
  when Symbol, String
@@ -36,19 +53,12 @@ class Anchormodel::ActiveModelTypeValueSingle < ActiveModel::Type::Value
36
53
  end
37
54
  end
38
55
 
39
- def serializable?(value)
56
+ def scalar_serializable?(value)
40
57
  return case value
41
- when Symbol, String
42
- @attribute.anchormodel_class.valid_keys.exclude?(value.to_sym)
43
- when nil, @attribute.anchormodel_class
58
+ when Symbol, String, nil, @attribute.anchormodel_class
44
59
  true
45
60
  else
46
61
  false
47
62
  end
48
63
  end
49
-
50
- def changed_in_place?(raw_old_value, value)
51
- old_value = deserialize(raw_old_value)
52
- old_value != value
53
- end
54
64
  end
data/lib/anchormodel.rb CHANGED
@@ -57,6 +57,7 @@ class Anchormodel
57
57
  end
58
58
 
59
59
  # Register self
60
+ fail("Duplicate anchor model key #{key.inspect} for #{self.class}.") if entries_hash.key?(key)
60
61
  entries_list << self
61
62
  entries_hash[key] = self
62
63
 
@@ -86,6 +86,45 @@ class UserTest < Minitest::Test
86
86
  assert_equal 0, User.guest.count
87
87
  end
88
88
 
89
+ # Regression: `where(anchormodel_col: %w[a b])` used to collapse to `IN (NULL)`
90
+ # because Single#serialize lacked Array handling. See memory `array-where-collapses-to-null`.
91
+ def test_where_with_array_of_keys
92
+ User.create!(role: :admin, locale: :en)
93
+ User.create!(role: :moderator, locale: :en)
94
+ User.create!(role: :guest, locale: :en)
95
+
96
+ sql = User.where(role: %w[admin moderator]).to_sql
97
+ assert_match(/admin/, sql)
98
+ assert_match(/moderator/, sql)
99
+ refute_match(/IN \(NULL\)/i, sql) # rubocop:disable Rails/RefuteMethods
100
+
101
+ assert_equal 2, User.where(role: %w[admin moderator]).count
102
+ assert_equal 2, User.where(role: %i[admin moderator]).count
103
+ assert_equal(
104
+ 2,
105
+ User.where(role: [Role.find(:admin), Role.find(:moderator)]).count
106
+ )
107
+ assert_equal 1, User.where.not(role: %w[admin moderator]).count
108
+ end
109
+
110
+ def test_where_with_array_of_invalid_keys_raises
111
+ assert_raises(RuntimeError) { User.where(role: %w[admin nope]).to_a }
112
+ end
113
+
114
+ # Direct probe on `serializable?` — guards against re-introducing the inverted
115
+ # `exclude?` logic that silently dropped valid keys from `HomogeneousIn` binds.
116
+ def test_serializable_predicate
117
+ type = User.type_for_attribute(:role)
118
+ assert type.serializable?('admin')
119
+ assert type.serializable?(:admin)
120
+ assert type.serializable?(Role.find(:admin))
121
+ assert type.serializable?(nil)
122
+ assert type.serializable?(%w[admin guest])
123
+ assert type.serializable?([:admin, Role.find(:guest)])
124
+ refute type.serializable?(42) # rubocop:disable Rails/RefuteMethods
125
+ refute type.serializable?([42]) # rubocop:disable Rails/RefuteMethods
126
+ end
127
+
89
128
  def test_model_readers_writers_with_different_class_name
90
129
  pia = User.new(locale: :en)
91
130
  pia.de!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anchormodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Kalbermatter
@@ -263,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
263
263
  - !ruby/object:Gem::Version
264
264
  version: '0'
265
265
  requirements: []
266
- rubygems_version: 3.6.9
266
+ rubygems_version: 4.0.11
267
267
  specification_version: 4
268
268
  summary: Bringing object-oriented programming to Rails enums
269
269
  test_files: []