Adds the magic `frozen_string_literal: true` comment to every file and
enables a Rubocop rule to make sure that it's always going to be there
going forward as well.
See here for more background [1], but the basic idea is that unlike many
other languages, static strings in code are mutable by default. This has
since been acknowledged as not a particularly good idea, and the
intention is to rectify the mistake when Ruby 3 comes out, where all
string literals will be frozen. The `frozen_string_literal` magic
comment was introduced in Ruby 2.3 as a way of easing the transition,
and allows libraries and projects to freeze their literals in advance.
I don't think this is breaking in any way: it's possible that users
might've been pulling out one of are literals somehow and mutating it,
but that would probably not have been useful for anything and would
certainly not be recommended, so I'm quite comfortable pushing this
change through as a minor version.
As discussed in #641.
[1] https://stackoverflow.com/a/37799399
Makes the `operations` argument to `nested_resource_class_methods`
required and adds explicit lists to any invocations that were missing
one.
The impetus here is that I think it's more easily digestible if each
call site is explicit about what operations it supports and therefore
which methods it's about to create on the class.
Excludes `idempotency_key` from opts to persist between API requests.
Obviously the same idempotency key is not something that we ever want to
use again.
Fixes#598.
We were previously using a bit of a hack to get a free deep copy
implementation through Ruby's marshaling framework. Lint call this out
as a security problem though, and rightfully so: when combined with
unsanitized user input, unmarshaling can result in very serious security
breaches involving arbitrary code execution.
This patch removes all uses of marshal/unmarshal in favor of
implementing a deep copy method for `StripeObject`. I also reworked some
of the constants around what keys are available for `opts`. I'm still
not completely happy with the results, but I think it's going to need a
slightly larger refactor in order to get somewhere truly good.
There is what could be a breaking change for people doing non-standard
stuff with the library: the opts that we copy with an object are now
whitelisted, so if they were being used to pass around extraneous data,
that might not work as expected anymore. But because this is a contract
that we never committed to, I don't think I'd bump the major version for
change.
I wanted to see what fixing Rubocop TODOs was like, so I tried to
eliminate all the easy ones. Most of these were pretty easy, and the
changes required are relatively minimal.
Some of the stuff left is harder. Pretty much everything under
`Metrics/*` is going to be a pretty big yak shave. A few of the others
are just going to need a little more work (e.g. `Style/ClassVars` and
`Style/GuardClause`). Going to stop here for now.
As described in #481, adding a protected field like `legal_entity` as
part of an update API operation can cause some issues like a custom
encoding scheme not being considered and special handling around empty
values being ignored.
As a an easy fix for this, let's disallow access to protected fields in
the same way that we disallow them from being set directly on an
instance of a given model.
Helps address (but is not a complete fix for) #481.
* Rename the `Update` operation to `Save`
* Add the `update` class method to all saveable resources
* Add tests for update method
* Add tests for plans, invoice items, and application fees
I'm not sure exactly what changed here (did we change the `$VERBOSE`
setting?), but I'm not seeing a whole lot of warnings when running the
test suites locally and in CI. For example:
```
Started
........................................./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
............../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
.../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
........./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
...
..../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
....../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
..../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
........./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
........../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
................./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
.../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
..../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
....../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
..........
........./home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
....../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
......../home/travis/build/stripe/stripe-ruby/lib/stripe/api_operations/list.rb:6: warning: instance variable @opts not initialized
............./home/travis/build/stripe/stripe-ruby/lib/stripe/stripe_object.rb:35: warning: instance variable @values not initialized
./home/travis/build/stripe/stripe-ruby/lib/stripe/stripe_object.rb:35: warning: instance variable @values not initialized
...................../home/travis/build/stripe/stripe-ruby/lib/stripe/transfer.rb:8: warning: instance variable @api_key not initialized
..............
..
Finished in 0.785621037 seconds.
```
Most of these are due to unused or uninitialized variables. This patch
fixes all warnings by fixing offending code.
This pull does two major things:
1. Refactors `serialize_params` to be more concise and readable while
still complying to our existing test suite. Unfortunately over time
this method has become a ball of mud that's very difficult to reason
about, as recently evidenced by #384.
2. Moves `serialize_params` from class method to instance method (while
still keeping for old class method for backwards compatibility). This
is to give it a more sane interface.
When additional filters were provided for pagination like an expansion
or a predicate, they would not propagate to any call after the first.
This patch addresses that issue by storing all filters and moving them
to any new page objects being created.
Fixes#331.
This dials down the safety of `StripeObject`'s `#update_attributes`
method so that it allows properties to be assigned that it doesn't yet
know about. We're doing this for a few reasons:
1. To reflect the current behavior of accessors (i.e. `obj.name = ...`)
through `method_missing`.
2. To allow `#update_attributes` to assign properties on new projects
that don't yet know their schema from an API call.
Fixes#324.
As discussed in #325, this deprecates the public visibility of
`#refresh_from` (by renaming it). It also adds some deprecation
infrastructure to produce warnings when it's used.
Lets not be too shy about just using `extend` instead of `include` here
when it's more appropriate to do so. The advantage to this approach is
that the module can be either extended _or_ included with this change,
but couldn't be without it due to the `ClassMethods` meta-magic.
List has already started doing this as of #314, so we don't have to be
afraid of breaking convention here.
Usage on a top-level collection:
```
Stripe::Customer.list.auto_paging_each do |customer|
puts customer
end
```
Usage on a subcollection:
``` ruby
customer.invoices.auto_paging_each do |invoice|
puts invoice
end
```
We've also renamed `#all` to `#list` to prevent confusion ("all" implies
that all resources are being returned, and in Stripe's paginated API
this was not the case). An alias has been provided for backward API
compatibility.
Fixes#167.
Replaces #211 and #248.
As detailed in issue #119, we've somewhat unfortunately been allowing
object attributes to be passed in during a #save because we mix any
arguments directly into the serialized hash (it seems that this was
originally intended to be used more for meta parameters that go to the
request).
As also noted in #119, this use causes problems when certain types of
parameters (like subobjects) are used. We're now left in the somewhat
awkward position of either:
1. Removing this functionality on #save and breaking what may be
behavior that people depend on.
2. Fully support this mass assignment.
This patch takes the second path by extracting a new #update_attributes
method and using it from #save. It's still far from a perfect approach
because keys that have the same name as certain options (e.g. `req_url`)
are not going to work, but it should capture the behavior that most
people want.
Fixes#119.
Modifies the behavior of an update so that it can create an object if it
was new. This allows an "upsert"-like functionality where the SDK will
tend to do the right/expected thing.
This is a tad janky in that it checks for the existence of a class-level
`.create` method which is expected to come from a different module, but
most modules in the project are already fairly deeply intertwined and
co-dependent.
Fixes#165.