brick 1.0.126 → 1.0.128
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/extensions.rb +117 -85
- data/lib/brick/frameworks/rails/engine.rb +44 -25
- data/lib/brick/frameworks/rails/form_builder.rb +12 -10
- data/lib/brick/version_number.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4465179ddef5435627439c7123bbb63e951abcda5bd8bd8e20952cca2fc9e274
|
4
|
+
data.tar.gz: b567eb687c8eea355ece80562a67e424629df4a8b64aae48596e6c6b01c730b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 162cf46af2e43b2652e59f9fe8f4d2826e490def50fb868869f614aacb256cfeecee3833dfb41807bef5ea64c83e921b7e993e728e6e42730a214ec49601de67
|
7
|
+
data.tar.gz: 15fdcc9b67bc82b55a195168e020575ca04d9d1ae5830e0d1bcd2c7e04944aba90238342cabc1c93b7b7d01619a369b1bb0a0383dbbe91666e796ffa4051aa55
|
data/lib/brick/extensions.rb
CHANGED
@@ -108,16 +108,16 @@ module ActiveRecord
|
|
108
108
|
dsl
|
109
109
|
end
|
110
110
|
|
111
|
-
def self.brick_parse_dsl(
|
112
|
-
unless
|
113
|
-
|
114
|
-
|
111
|
+
def self.brick_parse_dsl(join_array = nil, prefix = [], translations = {}, is_polymorphic = false, dsl = nil, emit_dsl = false)
|
112
|
+
unless join_array.is_a?(::Brick::JoinArray)
|
113
|
+
join_array = ::Brick::JoinArray.new.tap { |ary| ary.replace([join_array]) } if join_array.is_a?(::Brick::JoinHash)
|
114
|
+
join_array = ::Brick::JoinArray.new unless join_array.nil? || join_array.is_a?(Array)
|
115
115
|
end
|
116
116
|
prefix = [prefix] unless prefix.is_a?(Array)
|
117
117
|
members = []
|
118
118
|
unless dsl || (dsl = ::Brick.config.model_descrips[name] || brick_get_dsl)
|
119
119
|
# With no DSL available, still put this prefix into the JoinArray so we can get primary key (ID) info from this table
|
120
|
-
x = prefix.each_with_object(
|
120
|
+
x = prefix.each_with_object(join_array) { |v, s| s[v.to_sym] }
|
121
121
|
x[prefix.last] = nil unless prefix.empty? # Using []= will "hydrate" any missing part(s) in our whole series
|
122
122
|
return members
|
123
123
|
end
|
@@ -141,7 +141,7 @@ module ActiveRecord
|
|
141
141
|
if first_parts
|
142
142
|
if (parts = prefix + first_parts + [parts[-1]]).length > 1 && klass
|
143
143
|
unless is_polymorphic
|
144
|
-
s =
|
144
|
+
s = join_array
|
145
145
|
parts[0..-3].each { |v| s = s[v.to_sym] }
|
146
146
|
s[parts[-2]] = nil # unless parts[-2].empty? # Using []= will "hydrate" any missing part(s) in our whole series
|
147
147
|
end
|
@@ -153,7 +153,7 @@ module ActiveRecord
|
|
153
153
|
prefix << parts.shift until parts.empty?
|
154
154
|
end
|
155
155
|
# Expand this entry which refers to an association name
|
156
|
-
members2, dsl2a = klass.brick_parse_dsl(
|
156
|
+
members2, dsl2a = klass.brick_parse_dsl(join_array, prefix + [possible_dsl], translations, is_polymorphic, nil, true)
|
157
157
|
members += members2
|
158
158
|
dsl2 << dsl2a
|
159
159
|
dsl3 << dsl2a
|
@@ -434,7 +434,9 @@ module ActiveRecord
|
|
434
434
|
@brick_links ||= { '' => table_name }
|
435
435
|
end
|
436
436
|
|
437
|
-
def brick_select(params, selects = [], order_by = nil, translations = {},
|
437
|
+
def brick_select(params, selects = [], order_by = nil, translations = {},
|
438
|
+
join_array = ::Brick::JoinArray.new,
|
439
|
+
cust_col_override = nil)
|
438
440
|
is_add_bts = is_add_hms = true
|
439
441
|
|
440
442
|
# Build out cust_cols, bt_descrip and hm_counts now so that they are available on the
|
@@ -467,7 +469,7 @@ module ActiveRecord
|
|
467
469
|
is_distinct = true
|
468
470
|
distinct!
|
469
471
|
end
|
470
|
-
wheres[k] = v.split(',')
|
472
|
+
wheres[k] = v.is_a?(String) ? v.split(',') : v
|
471
473
|
end
|
472
474
|
|
473
475
|
# %%% Skip the metadata columns
|
@@ -506,84 +508,90 @@ module ActiveRecord
|
|
506
508
|
end
|
507
509
|
end
|
508
510
|
|
509
|
-
if join_array.present?
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
511
|
+
left_outer_joins!(join_array) if join_array.present?
|
512
|
+
|
513
|
+
# If it's a CollectionProxy (which inherits from Relation) then need to dig out the
|
514
|
+
# core Relation object which is found in the association scope.
|
515
|
+
rel_dupe = (is_a?(ActiveRecord::Associations::CollectionProxy) ? scope : self).dup
|
516
|
+
|
517
|
+
# Touching AREL AST walks the JoinDependency tree, and in that process uses our
|
518
|
+
# "brick_links" patch to find how every AR chain of association names relates to exact
|
519
|
+
# table correlation names chosen by AREL. We use a duplicate relation object for this
|
520
|
+
# because an important side-effect of referencing the AST is that the @arel instance
|
521
|
+
# variable gets set, and this is a signal to ActiveRecord that a relation has now
|
522
|
+
# become immutable. (We aren't quite ready for our "real deal" relation object to be
|
523
|
+
# set in stone ... still need to add .select(), and possibly .where() and .order()
|
524
|
+
# things ... also if there are any HM counts then an OUTER JOIN for each of them out
|
525
|
+
# to a derived table to do that counting. All of these things need to know proper
|
526
|
+
# table correlation names, which will now become available in brick_links on the
|
527
|
+
# rel_dupe object.)
|
528
|
+
rel_dupe.arel.ast
|
529
|
+
|
530
|
+
core_selects = selects.dup
|
531
|
+
id_for_tables = Hash.new { |h, k| h[k] = [] }
|
532
|
+
field_tbl_names = Hash.new { |h, k| h[k] = {} }
|
533
|
+
used_col_aliases = {} # Used to make sure there is not a name clash
|
534
|
+
|
535
|
+
# CUSTOM COLUMNS
|
536
|
+
# ==============
|
537
|
+
(cust_col_override || klass._br_cust_cols).each do |k, cc|
|
538
|
+
if rel_dupe.respond_to?(k) # Name already taken?
|
539
|
+
# %%% Use ensure_unique here in this kind of fashion:
|
540
|
+
# cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", bts, hms)
|
541
|
+
# binding.pry
|
542
|
+
next
|
543
|
+
end
|
538
544
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
end
|
561
|
-
end
|
562
|
-
used_col_aliases[col_alias] = nil
|
563
|
-
# Set up custom column links by preparing key_klass and key_alias
|
564
|
-
# (If there are multiple different tables referenced in the DSL, we end up creating a link to the last one)
|
565
|
-
if cc[2] && (dest_pk = dest_klass.primary_key)
|
566
|
-
key_klass = dest_klass
|
567
|
-
key_tbl_name = tbl_name
|
568
|
-
cc_part_idx = cc_part.length - 1
|
569
|
-
while cc_part_idx > 0 &&
|
570
|
-
(key_alias = "br_cc_#{k}__#{(cc_part[cc_part_idx..-2] + [dest_pk]).map(&:to_s).join('__')}") &&
|
571
|
-
key_alias != col_alias && # We break out if this key alias does exactly match the col_alias
|
572
|
-
used_col_aliases.key?(key_alias)
|
573
|
-
cc_part_idx -= 1
|
574
|
-
end
|
545
|
+
key_klass = nil
|
546
|
+
key_tbl_name = nil
|
547
|
+
dest_pk = nil
|
548
|
+
key_alias = nil
|
549
|
+
cc.first.each do |cc_part|
|
550
|
+
dest_klass = cc_part[0..-2].inject(klass) do |kl, cc_part_term|
|
551
|
+
# %%% Clear column info properly so we can do multiple subsequent requests
|
552
|
+
# binding.pry unless kl.reflect_on_association(cc_part_term)
|
553
|
+
kl.reflect_on_association(cc_part_term)&.klass || klass
|
554
|
+
end
|
555
|
+
tbl_name = rel_dupe.brick_links[cc_part[0..-2].map(&:to_s).join('.')]
|
556
|
+
# Deal with the conflict if there are two parts in the custom column named the same,
|
557
|
+
# "category.name" and "product.name" for instance will end up with aliases of "name"
|
558
|
+
# and "product__name".
|
559
|
+
if (cc_part_idx = cc_part.length - 1).zero?
|
560
|
+
col_alias = "br_cc_#{k}__#{table_name.tr('.', '_')}_#{cc_part.first}"
|
561
|
+
else
|
562
|
+
while cc_part_idx > 0 &&
|
563
|
+
(col_alias = "br_cc_#{k}__#{cc_part[cc_part_idx..-1].map(&:to_s).join('__').tr('.', '_')}") &&
|
564
|
+
used_col_aliases.key?(col_alias)
|
565
|
+
cc_part_idx -= 1
|
575
566
|
end
|
576
|
-
selects << "#{tbl_name}.#{cc_part.last} AS #{col_alias}"
|
577
|
-
cc_part << col_alias
|
578
567
|
end
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
568
|
+
used_col_aliases[col_alias] = nil
|
569
|
+
# Set up custom column links by preparing key_klass and key_alias
|
570
|
+
# (If there are multiple different tables referenced in the DSL, we end up creating a link to the last one)
|
571
|
+
if cc[2] && (dest_pk = dest_klass.primary_key)
|
572
|
+
key_klass = dest_klass
|
573
|
+
key_tbl_name = tbl_name
|
574
|
+
cc_part_idx = cc_part.length - 1
|
575
|
+
while cc_part_idx > 0 &&
|
576
|
+
(key_alias = "br_cc_#{k}__#{(cc_part[cc_part_idx..-2] + [dest_pk]).map(&:to_s).join('__')}") &&
|
577
|
+
key_alias != col_alias && # We break out if this key alias does exactly match the col_alias
|
578
|
+
used_col_aliases.key?(key_alias)
|
579
|
+
cc_part_idx -= 1
|
580
|
+
end
|
583
581
|
end
|
584
|
-
|
582
|
+
selects << "#{tbl_name}.#{cc_part.last} AS #{col_alias}"
|
583
|
+
cc_part << col_alias
|
585
584
|
end
|
585
|
+
# Add a key column unless we've already got it
|
586
|
+
if key_alias && !used_col_aliases.key?(key_alias)
|
587
|
+
selects << "#{key_tbl_name}.#{dest_pk} AS #{key_alias}"
|
588
|
+
used_col_aliases[key_alias] = nil
|
589
|
+
end
|
590
|
+
cc[2] = key_alias ? [key_klass, key_alias] : nil
|
591
|
+
end
|
586
592
|
|
593
|
+
# LEFT OUTER JOINs
|
594
|
+
unless cust_col_override
|
587
595
|
klass._br_bt_descrip.each do |v|
|
588
596
|
v.last.each do |k1, v1| # k1 is class, v1 is array of columns to snag
|
589
597
|
next unless (tbl_name = rel_dupe.brick_links[v.first.to_s]&.split('.')&.last)
|
@@ -644,6 +652,7 @@ module ActiveRecord
|
|
644
652
|
_assoc_names[assoc_name] = [table_alias, klass]
|
645
653
|
end
|
646
654
|
end
|
655
|
+
|
647
656
|
# Add derived table JOIN for the has_many counts
|
648
657
|
nix = []
|
649
658
|
klass._br_hm_counts.each do |k, hm|
|
@@ -781,7 +790,7 @@ module ActiveRecord
|
|
781
790
|
JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', ')}, COUNT(#{'DISTINCT ' if hm.options[:through]}#{count_column
|
782
791
|
}) AS c_t_ FROM #{from_clause || hm_table_name} GROUP BY #{group_bys.join(', ')}) #{tbl_alias}"
|
783
792
|
self.joins_values |= ["#{join_clause} ON #{on_clause.join(' AND ')}"] # Same as: joins!(...)
|
784
|
-
end
|
793
|
+
end unless cust_col_override
|
785
794
|
while (n = nix.pop)
|
786
795
|
klass._br_hm_counts.delete(n)
|
787
796
|
end
|
@@ -851,6 +860,19 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
851
860
|
wheres unless wheres.empty? # Return the specific parameters that we did use
|
852
861
|
end
|
853
862
|
|
863
|
+
# Build out an AR relation that queries for a list of objects, and include all the appropriate JOINs to later apply DSL using #brick_descrip
|
864
|
+
def brick_list
|
865
|
+
pks = klass.primary_key.is_a?(String) ? [klass.primary_key] : klass.primary_key
|
866
|
+
selects = pks.each_with_object([]) { |pk, s| s << pk unless s.include?(pk) }
|
867
|
+
pieces, my_dsl = klass.brick_parse_dsl(join_array = ::Brick::JoinArray.new, [], translations = {}, false, nil, true)
|
868
|
+
brick_select(
|
869
|
+
where_values_hash, selects, nil, translations, join_array,
|
870
|
+
{ '_br' => (descrip_cols = [pieces, my_dsl]) }
|
871
|
+
)
|
872
|
+
order_values = klass.primary_key
|
873
|
+
[self.select(selects), descrip_cols]
|
874
|
+
end
|
875
|
+
|
854
876
|
private
|
855
877
|
|
856
878
|
def shift_or_first(ary)
|
@@ -1254,6 +1276,11 @@ class Object
|
|
1254
1276
|
end
|
1255
1277
|
self.abstract_class = true
|
1256
1278
|
code << " self.abstract_class = true\n"
|
1279
|
+
elsif Object.const_defined?('BCrypt') && relation[:cols].include?('password_digest') &&
|
1280
|
+
!instance_methods.include?(:password) && respond_to?(:has_secure_password)
|
1281
|
+
puts "Appears that the #{full_name} model is intended to hold user account information. Applying #has_secure_password."
|
1282
|
+
has_secure_password
|
1283
|
+
code << " has_secure_password\n"
|
1257
1284
|
end
|
1258
1285
|
# Accommodate singular or camel-cased table names such as "order_detail" or "OrderDetails"
|
1259
1286
|
code << " self.table_name = '#{self.table_name = matching}'\n" if inheritable_name || table_name != matching
|
@@ -2718,12 +2745,17 @@ module Brick
|
|
2718
2745
|
end
|
2719
2746
|
end
|
2720
2747
|
::Brick.relations.map do |k, v|
|
2748
|
+
# next if Brick.config.exclude_tables.include?(k)
|
2749
|
+
|
2721
2750
|
tbl_parts = k.split('.')
|
2722
2751
|
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first == ::Brick.apartment_default_tenant
|
2723
2752
|
res = tbl_parts.join('.')
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2753
|
+
table_name = (model = models[res])&.last&.table_name
|
2754
|
+
table_name ||= begin
|
2755
|
+
v[:class_name].constantize.table_name
|
2756
|
+
rescue
|
2757
|
+
end
|
2758
|
+
[k, table_name || k, migrations&.fetch(res, nil), model&.first]
|
2727
2759
|
end
|
2728
2760
|
end
|
2729
2761
|
|
@@ -1602,7 +1602,15 @@ end
|
|
1602
1602
|
if bt.length < 4
|
1603
1603
|
bt << (option_detail = [[\"(No #\{bt_name\} chosen)\", '^^^brick_NULL^^^']])
|
1604
1604
|
# %%% Accommodate composite keys for obj.pk at the end here
|
1605
|
-
bt_class&.order(obj_pk = bt_class.primary_key)
|
1605
|
+
collection, descrip_cols = bt_class&.order(obj_pk = bt_class.primary_key).brick_list
|
1606
|
+
collection&.each do |obj|
|
1607
|
+
option_detail << [
|
1608
|
+
obj.brick_descrip(
|
1609
|
+
descrip_cols&.first&.map { |col| obj.send(col.last) },
|
1610
|
+
obj_pk
|
1611
|
+
), obj.send(obj_pk)
|
1612
|
+
]
|
1613
|
+
end
|
1606
1614
|
end %>
|
1607
1615
|
BT <%= bt_class&.bt_link(bt.first) || orig_poly_name %>
|
1608
1616
|
<% else %>
|
@@ -1634,34 +1642,45 @@ end
|
|
1634
1642
|
obj_pk = (pk.is_a?(Array) ? pk : [pk]).each_with_object([]) { |pk_part, s| s << "#{hm_singular_name}.#{pk_part}" }.join(', ')
|
1635
1643
|
poly_fix = if (poly_type = (hm.first.options[:as] && hm.first.type))
|
1636
1644
|
"
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
#{
|
1643
|
-
"
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1645
|
+
# Let's fix an unexpected \"feature\" of AR -- when going through a polymorphic has_many
|
1646
|
+
# association that points to an STI model then filtering for the __able_type column is done
|
1647
|
+
# with a .where(). And the polymorphic class name it points to is the base class name of
|
1648
|
+
# the STI model instead of its subclass.
|
1649
|
+
poly_type = #{poly_type.inspect}
|
1650
|
+
#{ (inh_col = @_brick_model.inheritance_column).present? &&
|
1651
|
+
" if poly_type && @#{obj_name}.respond_to?(:#{inh_col}) &&
|
1652
|
+
(base_type = collection.where_values_hash[poly_type])
|
1653
|
+
collection = collection.rewhere(poly_type => [base_type, @#{obj_name}.#{inh_col}])
|
1654
|
+
end"}"
|
1647
1655
|
end
|
1648
1656
|
s << "<table id=\"#{hm_name}\" class=\"shadow\">
|
1649
1657
|
<tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}</th></tr>
|
1650
|
-
<%
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1658
|
+
<% if (assoc = @#{obj_name}.class.reflect_on_association(:#{hm_name})).macro == :has_one &&
|
1659
|
+
assoc.options&.fetch(:through, nil).nil?
|
1660
|
+
# In order to apply DSL properly, evaluate this HO the other way around as if it were as a BT
|
1661
|
+
collection = assoc.klass.where(assoc.foreign_key => @#{obj_name}.#{pk})
|
1662
|
+
collection = collection.instance_exec(&assoc.scopes.first) if assoc.scopes.present?
|
1663
|
+
else
|
1664
|
+
collection = @#{obj_name}.#{hm_name}
|
1665
|
+
end
|
1666
|
+
case collection
|
1667
|
+
when ActiveRecord::Relation # has_many (which comes in as a CollectionProxy) or a has_one#{
|
1668
|
+
poly_fix}
|
1669
|
+
collection2, descrip_cols = collection.brick_list
|
1670
|
+
when ActiveRecord::Base # Object from a has_one :through
|
1671
|
+
collection2 = [collection]
|
1672
|
+
else # We get an array back when AR < 4.2
|
1673
|
+
collection2 = collection.to_a.compact
|
1674
|
+
end
|
1675
|
+
collection2 = collection2.uniq
|
1676
|
+
if collection2.empty? %>
|
1661
1677
|
<tr><td>(none)</td></tr>
|
1662
|
-
|
1663
|
-
|
1664
|
-
<tr><td><%=
|
1678
|
+
<% else
|
1679
|
+
collection2.each do |#{hm_singular_name}| %>
|
1680
|
+
<tr><td><%= br_descrip = #{hm_singular_name}.brick_descrip(
|
1681
|
+
descrip_cols&.first&.map { |col| #{hm_singular_name}.send(col.last) }
|
1682
|
+
)
|
1683
|
+
link_to(br_descrip, #{hm.first.klass._brick_index(:singular)}_path(slashify(#{obj_pk}))) %></td></tr>
|
1665
1684
|
<% end %>
|
1666
1685
|
<% end %>
|
1667
1686
|
</table>"
|
@@ -5,7 +5,8 @@ module Brick::Rails::FormBuilder
|
|
5
5
|
# @_text_fields_present - To include trix editor
|
6
6
|
# @_date_fields_present - To include flatpickr date / time editor
|
7
7
|
# @_json_fields_present - To include JSONEditor
|
8
|
-
def brick_field(method, html_options = {}, val = nil, col = nil,
|
8
|
+
def brick_field(method, html_options = {}, val = nil, col = nil,
|
9
|
+
bt = nil, bt_class = nil, bt_name = nil, bt_pair = nil)
|
9
10
|
model = self.object.class
|
10
11
|
col ||= model.columns_hash[method]
|
11
12
|
out = +'<table><tr><td>'
|
@@ -19,15 +20,16 @@ module Brick::Rails::FormBuilder
|
|
19
20
|
|
20
21
|
html_options[:prompt] = "Select #{bt_name}"
|
21
22
|
out << self.select(method.to_sym, bt[3], { value: val || '^^^brick_NULL^^^' }, html_options)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
bt_link = if (bt_obj = bt_class&.find_by(bt_pair[1] => val))
|
24
|
+
bt_path = template.send(
|
25
|
+
"#{bt_class.base_class._brick_index(:singular)}_path".to_sym,
|
26
|
+
bt_obj.send(bt_class.primary_key.to_sym)
|
27
|
+
)
|
28
|
+
template.link_to('⇛', bt_path, { class: 'show-arrow' })
|
29
|
+
elsif val
|
30
|
+
"<span class=\"orphan\">Orphaned ID: #{val}</span>".html_safe
|
31
|
+
end
|
32
|
+
out << bt_link if bt_link
|
31
33
|
elsif @_brick_monetized_attributes&.include?(method)
|
32
34
|
out << self.text_field(method.to_sym, html_options.merge({ value: Money.new(val.to_i).format }))
|
33
35
|
else
|
data/lib/brick/version_number.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.128
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|