protip 0.18.5 → 0.18.6
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 +4 -4
- data/lib/protip/resource.rb +22 -6
- data/lib/protip/wrapper.rb +6 -12
- data/test/unit/protip/resource_test.rb +138 -23
- data/test/unit/protip/wrapper_test.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9c25de6d9f409c5bb8c1659951ecc4fa10a5aa4
|
4
|
+
data.tar.gz: aab7d4182c10f0a540dd5762ea3921dac899c2b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 530e2c08bf013f25afea7d4be6eb254b85b192fb8ca374ceb09ef48ce3e9e703926ca07335bac5396edcacc129f29710cb2cb9e1b619508210ba39c8170335f9
|
7
|
+
data.tar.gz: d65a08e07c0365afadfdf614f731bcf5939deed2e463f4e3d4159f70b0691e1d9735567f33dd1edcf0d7c893f919a128f01e0e634aceec33c4761422aa502e81
|
data/lib/protip/resource.rb
CHANGED
@@ -132,12 +132,13 @@ module Protip
|
|
132
132
|
end
|
133
133
|
|
134
134
|
define_method "#{field.name}=" do |new_value|
|
135
|
-
|
135
|
+
old_value = self.message[field.name] # Only compare the raw values
|
136
136
|
@wrapper.send("#{field.name}=", new_value)
|
137
|
-
|
137
|
+
new_value = self.message[field.name]
|
138
138
|
|
139
|
-
#
|
140
|
-
|
139
|
+
# Need to check that types are the same first, otherwise protobuf gets mad comparing
|
140
|
+
# messages with non-messages
|
141
|
+
send("#{field.name}_will_change!") unless new_value.class == old_value.class && new_value == old_value
|
141
142
|
end
|
142
143
|
|
143
144
|
# needed for ActiveModel::Dirty
|
@@ -263,8 +264,23 @@ module Protip
|
|
263
264
|
end
|
264
265
|
|
265
266
|
def assign_attributes(attributes)
|
266
|
-
|
267
|
-
|
267
|
+
old_attributes = {}
|
268
|
+
descriptor = message.class.descriptor
|
269
|
+
attributes.keys.each do |key|
|
270
|
+
field = descriptor.lookup(key.to_s)
|
271
|
+
value = message[key.to_s]
|
272
|
+
# If the current value is a message, we need to clone it to get a reasonable comparison later,
|
273
|
+
# since we might just assign attributes to the current instance of the message directly
|
274
|
+
old_attributes[key] = field && field.type == :message && value ? value.clone : value
|
275
|
+
end
|
276
|
+
@wrapper.assign_attributes attributes
|
277
|
+
attributes.keys.each do |key|
|
278
|
+
old_value = old_attributes[key]
|
279
|
+
new_value = message[key.to_s]
|
280
|
+
unless old_value.class == new_value.class && old_value == new_value
|
281
|
+
send "#{key}_will_change!"
|
282
|
+
end
|
283
|
+
end
|
268
284
|
nil # return nil to match ActiveRecord behavior
|
269
285
|
end
|
270
286
|
|
data/lib/protip/wrapper.rb
CHANGED
@@ -115,17 +115,11 @@ module Protip
|
|
115
115
|
field = message.class.descriptor.lookup(field_name.to_s) ||
|
116
116
|
(raise ArgumentError.new("Unrecognized field: #{field_name}"))
|
117
117
|
|
118
|
-
# For inconvertible nested messages,
|
119
|
-
if field.type == :message && !converter.convertible?(field.subtype.msgclass)
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
wrapper = get(field) || build(field.name) # Create the field if it doesn't already exist
|
124
|
-
wrapper.assign_attributes value
|
125
|
-
else # If value is a simple type (e.g. nil), set the value directly
|
126
|
-
set(field, value)
|
127
|
-
end
|
128
|
-
# Otherwise, if the field is a convertible message or a simple type, we set the value directly
|
118
|
+
# For inconvertible nested messages, we allow a hash to be passed in with nested attributes
|
119
|
+
if field.type == :message && !converter.convertible?(field.subtype.msgclass) && value.is_a?(Hash)
|
120
|
+
wrapper = get(field) || build(field.name) # Create the field if it doesn't already exist
|
121
|
+
wrapper.assign_attributes value
|
122
|
+
# Otherwise, if the field is a message (convertible or not) or a simple type, we set the value directly
|
129
123
|
else
|
130
124
|
set(field, value)
|
131
125
|
end
|
@@ -224,7 +218,7 @@ module Protip
|
|
224
218
|
elsif nested_resources.has_key?(field.name.to_sym)
|
225
219
|
value.message
|
226
220
|
else
|
227
|
-
raise ArgumentError.new "Cannot convert from Ruby object: \"#{field}\""
|
221
|
+
raise ArgumentError.new "Cannot convert from Ruby object: \"#{field.name}\""
|
228
222
|
end
|
229
223
|
elsif field.type == :enum
|
230
224
|
value.is_a?(Fixnum) ? value : value.to_sym
|
@@ -515,9 +515,97 @@ module Protip::ResourceTest # Namespace for internal constants
|
|
515
515
|
attrs = {id: 2}
|
516
516
|
assert_equal resource_message_class.new(attrs), resource_class.new(attrs).message
|
517
517
|
end
|
518
|
+
|
519
|
+
it 'allows nested attributes to be given' do
|
520
|
+
attrs = {
|
521
|
+
nested_message: {
|
522
|
+
number: 3
|
523
|
+
}
|
524
|
+
}
|
525
|
+
assert_equal nested_message_class.new(number: 3), resource_class.new(attrs).message.nested_message
|
526
|
+
end
|
518
527
|
end
|
519
528
|
end
|
520
529
|
|
530
|
+
# Shared behavior for direct setters and #assign_attributes. The setter object must be able to be
|
531
|
+
# initialized as +setter_class.new(resource)+, and must respond to +setter.set({field => value, field2 => value2})+
|
532
|
+
# by performing the appropriate operation (e.g. +.field=+ or +.assign_attributes+).
|
533
|
+
def self.describe_dirty_attributes_setter(setter_class)
|
534
|
+
|
535
|
+
describe 'dirty attributes' do
|
536
|
+
let :converter do
|
537
|
+
Class.new do
|
538
|
+
include Protip::Converter
|
539
|
+
end.new
|
540
|
+
end
|
541
|
+
|
542
|
+
let :resource do
|
543
|
+
resource_class.new resource_message_class.new({
|
544
|
+
string: 'foo',
|
545
|
+
nested_message: nested_message_class.new(number: 32)
|
546
|
+
})
|
547
|
+
end
|
548
|
+
|
549
|
+
let :setter do
|
550
|
+
setter_class.new(resource)
|
551
|
+
end
|
552
|
+
|
553
|
+
before do
|
554
|
+
resource_class.converter = converter
|
555
|
+
raise 'sanity check failed' if resource.changed? || resource.string_changed? || resource.nested_message_changed?
|
556
|
+
end
|
557
|
+
|
558
|
+
it 'recognizes changes in scalar values' do
|
559
|
+
setter.set string: 'bar'
|
560
|
+
assert resource.changed?, 'resource was not marked as changed'
|
561
|
+
assert resource.string_changed?, 'field was not marked as changed'
|
562
|
+
end
|
563
|
+
|
564
|
+
it 'recognizes when scalar values do not change' do
|
565
|
+
setter.set string: 'foo'
|
566
|
+
refute resource.changed?, 'resource was marked as changed'
|
567
|
+
refute resource.string_changed?, 'field was marked as changed'
|
568
|
+
end
|
569
|
+
|
570
|
+
describe '(message attributes)' do
|
571
|
+
before do
|
572
|
+
converter.stubs(:convertible?).with(nested_message_class).returns(true)
|
573
|
+
converter.stubs(:to_message).with(42, nested_message_class).returns(nested_message_class.new(number: 52))
|
574
|
+
converter.stubs(:to_object).with(nested_message_class.new(number: 52)).returns(42)
|
575
|
+
converter.stubs(:to_object).with(nested_message_class.new(number: 62)).returns(72)
|
576
|
+
end
|
577
|
+
it 'marks convertible messages as changed if they are changed as Ruby values' do
|
578
|
+
setter.set nested_message: 42
|
579
|
+
assert resource.changed?, 'resource was not marked as changed'
|
580
|
+
assert resource.nested_message_changed?, 'field was not marked as changed'
|
581
|
+
end
|
582
|
+
it 'marks sub-messages as changed if they are changed as messages' do
|
583
|
+
setter.set nested_message: nested_message_class.new(number: 62)
|
584
|
+
assert resource.changed?, 'resource was not marked as changed'
|
585
|
+
assert resource.nested_message_changed?, 'field was not marked as changed'
|
586
|
+
end
|
587
|
+
it 'marks sub-messages as changed when they are nullified' do
|
588
|
+
setter.set nested_message: nil
|
589
|
+
assert resource.changed?, 'resource was not marked as changed'
|
590
|
+
assert resource.nested_message_changed?, 'field was not marked as changed'
|
591
|
+
end
|
592
|
+
it 'recognizes when convertible messages are not changed when set as Ruby values' do
|
593
|
+
resource.message.nested_message.number = 52
|
594
|
+
raise 'sanity check failed' if resource.changed? || resource.nested_message_changed?
|
595
|
+
setter.set nested_message: 42
|
596
|
+
refute resource.changed?, 'resource was marked as changed'
|
597
|
+
refute resource.string_changed?, 'field was marked as changed'
|
598
|
+
end
|
599
|
+
it 'recognizes when sub-messages are not changed when set as messages' do
|
600
|
+
setter.set nested_message: nested_message_class.new(number: 32)
|
601
|
+
refute resource.changed?, 'resource was marked as changed'
|
602
|
+
refute resource.string_changed?, 'field was marked as changed'
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
|
521
609
|
describe 'attribute writer' do
|
522
610
|
before do
|
523
611
|
resource_class.class_exec(resource_message_class) do |resource_message_class|
|
@@ -532,24 +620,11 @@ module Protip::ResourceTest # Namespace for internal constants
|
|
532
620
|
resource.string = test_string
|
533
621
|
end
|
534
622
|
|
535
|
-
|
536
|
-
resource =
|
537
|
-
resource.
|
538
|
-
assert resource.changed?, 'resource should be marked as changed'
|
539
|
-
assert resource.string_changed?, 'string field should be marked as changed'
|
540
|
-
end
|
541
|
-
|
542
|
-
it 'does not mark the resource and attribute as changed if the value is not changed' do
|
543
|
-
resource = resource_class.new string: 'original'
|
544
|
-
resource.send :changes_applied # clear the changes
|
545
|
-
# establish that the changes were cleared
|
546
|
-
assert !resource.changed?, 'resource should be not marked as changed'
|
547
|
-
assert !resource.string_changed?, 'string field should not be marked as changed'
|
548
|
-
|
549
|
-
resource.string = 'original'
|
550
|
-
assert !resource.changed?, 'resource should be not marked as changed'
|
551
|
-
assert !resource.string_changed?, 'string field should not be marked as changed'
|
623
|
+
setter_class = Class.new do
|
624
|
+
def initialize(resource) ; @resource = resource ; end
|
625
|
+
def set(attributes) ; attributes.each{|attribute, value| @resource.public_send(:"#{attribute}=", value)} ; end
|
552
626
|
end
|
627
|
+
describe_dirty_attributes_setter(setter_class)
|
553
628
|
end
|
554
629
|
|
555
630
|
describe '#assign_attributes' do
|
@@ -559,15 +634,55 @@ module Protip::ResourceTest # Namespace for internal constants
|
|
559
634
|
end
|
560
635
|
end
|
561
636
|
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
637
|
+
let :resource do
|
638
|
+
resource_class.new
|
639
|
+
end
|
640
|
+
|
641
|
+
it 'delegates to #assign_attributes on the wrapper' do
|
642
|
+
# Instantiate the resource before setting the expectation, since assign_attributes is allowed to be
|
643
|
+
# called during #initialize as well
|
644
|
+
resource
|
645
|
+
|
646
|
+
Protip::Wrapper.any_instance.expects(:assign_attributes).with(string: 'foo')
|
647
|
+
resource.assign_attributes string: 'foo'
|
648
|
+
end
|
649
|
+
|
650
|
+
setter_class = Class.new do
|
651
|
+
def initialize(resource) ; @resource = resource ; end
|
652
|
+
def set(attributes) ; @resource.assign_attributes attributes ; end
|
653
|
+
end
|
654
|
+
describe_dirty_attributes_setter setter_class
|
655
|
+
describe 'dirty attributes (nested hashes)' do
|
656
|
+
|
657
|
+
it 'marks nested hashes as changed if they set a new field' do
|
658
|
+
resource.assign_attributes nested_message: {number: 52}
|
659
|
+
assert resource.changed?, 'resource was not marked as changed'
|
660
|
+
assert resource.nested_message_changed?, 'field was not marked as changed'
|
661
|
+
end
|
662
|
+
|
663
|
+
describe '(when a nested message has an initial value)' do
|
664
|
+
before do
|
665
|
+
resource.nested_message = nested_message_class.new(number: 32)
|
666
|
+
resource.send(:changes_applied) # Clear the list of changes
|
667
|
+
# Sanity check
|
668
|
+
raise 'unexpected' if resource.changed? || resource.string_changed? || resource.nested_message_changed?
|
669
|
+
end
|
670
|
+
|
671
|
+
it 'marks nested hashes as changed if they change a field' do
|
672
|
+
resource.assign_attributes nested_message: {number: 42}
|
673
|
+
assert resource.changed?, 'resource was not marked as changed'
|
674
|
+
assert resource.nested_message_changed?, 'field was not marked as changed'
|
675
|
+
end
|
676
|
+
|
677
|
+
it 'does not mark nested hashes as changed if they do not change the underlying message' do
|
678
|
+
resource.assign_attributes nested_message: {number: 32}
|
679
|
+
refute resource.changed?, 'resource was marked as changed'
|
680
|
+
refute resource.nested_message_changed?, 'field was marked as changed'
|
681
|
+
end
|
682
|
+
end
|
567
683
|
end
|
568
684
|
|
569
685
|
it 'returns nil' do
|
570
|
-
resource = resource_class.new
|
571
686
|
assert_nil resource.assign_attributes(string: 'asdf')
|
572
687
|
end
|
573
688
|
end
|
@@ -255,7 +255,7 @@ module Protip::WrapperTest # namespace for internal constants
|
|
255
255
|
wrapper.assign_attributes inner: {value: 50, note: 'noted'}
|
256
256
|
end
|
257
257
|
|
258
|
-
it
|
258
|
+
it 'sets message fields to nil when they\'re assigned nil' do
|
259
259
|
wrapped_message.inner = inner_message_class.new(value: 60)
|
260
260
|
assert wrapped_message.inner
|
261
261
|
wrapper.assign_attributes inner: nil
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.18.
|
4
|
+
version: 0.18.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AngelList
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|