fmrest 0.10.0 → 0.13.0

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +38 -0
  4. data/README.md +194 -763
  5. metadata +70 -97
  6. data/.gitignore +0 -26
  7. data/.rspec +0 -3
  8. data/.travis.yml +0 -5
  9. data/Gemfile +0 -3
  10. data/Rakefile +0 -6
  11. data/fmrest.gemspec +0 -38
  12. data/lib/fmrest.rb +0 -29
  13. data/lib/fmrest/errors.rb +0 -28
  14. data/lib/fmrest/spyke.rb +0 -21
  15. data/lib/fmrest/spyke/base.rb +0 -23
  16. data/lib/fmrest/spyke/container_field.rb +0 -59
  17. data/lib/fmrest/spyke/model.rb +0 -36
  18. data/lib/fmrest/spyke/model/associations.rb +0 -82
  19. data/lib/fmrest/spyke/model/attributes.rb +0 -171
  20. data/lib/fmrest/spyke/model/auth.rb +0 -35
  21. data/lib/fmrest/spyke/model/connection.rb +0 -74
  22. data/lib/fmrest/spyke/model/container_fields.rb +0 -25
  23. data/lib/fmrest/spyke/model/global_fields.rb +0 -40
  24. data/lib/fmrest/spyke/model/http.rb +0 -37
  25. data/lib/fmrest/spyke/model/orm.rb +0 -212
  26. data/lib/fmrest/spyke/model/serialization.rb +0 -91
  27. data/lib/fmrest/spyke/model/uri.rb +0 -30
  28. data/lib/fmrest/spyke/portal.rb +0 -55
  29. data/lib/fmrest/spyke/relation.rb +0 -359
  30. data/lib/fmrest/spyke/spyke_formatter.rb +0 -273
  31. data/lib/fmrest/spyke/validation_error.rb +0 -25
  32. data/lib/fmrest/string_date.rb +0 -220
  33. data/lib/fmrest/token_store.rb +0 -6
  34. data/lib/fmrest/token_store/active_record.rb +0 -74
  35. data/lib/fmrest/token_store/base.rb +0 -25
  36. data/lib/fmrest/token_store/memory.rb +0 -26
  37. data/lib/fmrest/token_store/moneta.rb +0 -41
  38. data/lib/fmrest/token_store/redis.rb +0 -45
  39. data/lib/fmrest/v1.rb +0 -21
  40. data/lib/fmrest/v1/connection.rb +0 -89
  41. data/lib/fmrest/v1/container_fields.rb +0 -114
  42. data/lib/fmrest/v1/dates.rb +0 -81
  43. data/lib/fmrest/v1/paths.rb +0 -47
  44. data/lib/fmrest/v1/raise_errors.rb +0 -57
  45. data/lib/fmrest/v1/token_session.rb +0 -142
  46. data/lib/fmrest/v1/token_store/active_record.rb +0 -13
  47. data/lib/fmrest/v1/token_store/memory.rb +0 -13
  48. data/lib/fmrest/v1/type_coercer.rb +0 -192
  49. data/lib/fmrest/v1/utils.rb +0 -95
  50. data/lib/fmrest/version.rb +0 -5
data/lib/fmrest/spyke.rb DELETED
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require "spyke"
5
- rescue LoadError => e
6
- e.message << " (Did you include Spyke in your Gemfile?)" unless e.message.frozen?
7
- raise e
8
- end
9
-
10
- require "fmrest"
11
- require "fmrest/spyke/spyke_formatter"
12
- require "fmrest/spyke/model"
13
- require "fmrest/spyke/base"
14
-
15
- module FmRest
16
- module Spyke
17
- def self.included(base)
18
- base.include Model
19
- end
20
- end
21
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module Spyke
5
- class Base < ::Spyke::Base
6
- include FmRest::Spyke::Model
7
- end
8
-
9
- class << self
10
- def Base(config = nil)
11
- warn "[DEPRECATION] Inheriting from `FmRest::Spyke::Base(config)` is deprecated and will be removed, inherit from `FmRest::Spyke::Base` (without arguments) and use `fmrest_config=` instead"
12
-
13
- if config
14
- return Class.new(::FmRest::Spyke::Base) do
15
- self.fmrest_config = config
16
- end
17
- end
18
-
19
- ::FmRest::Spyke::Base
20
- end
21
- end
22
- end
23
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module Spyke
5
- class ContainerField
6
-
7
- # @return [String] the name of the container field
8
- attr_reader :name
9
-
10
- # @param base [FmRest::Spyke::Base] the record this container belongs to
11
- # @param name [Symbol] the name of the container field
12
- def initialize(base, name)
13
- @base = base
14
- @name = name
15
- end
16
-
17
- # @return [String] the URL for the container
18
- def url
19
- @base.attributes[name]
20
- end
21
-
22
- # @return (see FmRest::V1::ContainerFields#fetch_container_data)
23
- def download
24
- FmRest::V1.fetch_container_data(url, @base.class.connection)
25
- end
26
-
27
- # @param filename_or_io [String, IO] a path to the file to upload or an
28
- # IO object
29
- # @param options [Hash]
30
- # @option options [Integer] :repetition (1) The repetition to pass to the
31
- # upload URL
32
- # @option (see FmRest::V1::ContainerFields#upload_container_data)
33
- def upload(filename_or_io, options = {})
34
- raise ArgumentError, "Record needs to be saved before uploading to a container field" unless @base.persisted?
35
-
36
- response =
37
- FmRest::V1.upload_container_data(
38
- @base.class.connection,
39
- upload_path(options[:repetition] || 1),
40
- filename_or_io,
41
- options
42
- )
43
-
44
- # Update mod id on record
45
- @base.mod_id = response.body[:data][:mod_id]
46
-
47
- true
48
- end
49
-
50
- private
51
-
52
- # @param repetition [Integer]
53
- # @return [String] the path for uploading a file to the container
54
- def upload_path(repetition)
55
- FmRest::V1.container_field_path(@base.class.layout, @base.id, name, repetition)
56
- end
57
- end
58
- end
59
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/spyke/model/connection"
4
- require "fmrest/spyke/model/uri"
5
- require "fmrest/spyke/model/attributes"
6
- require "fmrest/spyke/model/serialization"
7
- require "fmrest/spyke/model/associations"
8
- require "fmrest/spyke/model/orm"
9
- require "fmrest/spyke/model/container_fields"
10
- require "fmrest/spyke/model/global_fields"
11
- require "fmrest/spyke/model/http"
12
- require "fmrest/spyke/model/auth"
13
-
14
- module FmRest
15
- module Spyke
16
- module Model
17
- extend ::ActiveSupport::Concern
18
-
19
- include Connection
20
- include Uri
21
- include Attributes
22
- include Serialization
23
- include Associations
24
- include Orm
25
- include ContainerFields
26
- include GlobalFields
27
- include Http
28
- include Auth
29
-
30
- included do
31
- # @return [Integer] the record's modId
32
- attr_accessor :mod_id
33
- end
34
- end
35
- end
36
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/spyke/portal"
4
-
5
- module FmRest
6
- module Spyke
7
- module Model
8
- module Associations
9
- extend ::ActiveSupport::Concern
10
-
11
- included do
12
- # Keep track of portal options by their FM keys as we could need it
13
- # to parse the portalData JSON in SpykeFormatter
14
- class_attribute :portal_options, instance_accessor: false, instance_predicate: false
15
-
16
- # class_attribute supports a :default option since ActiveSupport 5.2,
17
- # but we want to support previous versions too so we set the default
18
- # manually instead
19
- self.portal_options = {}.freeze
20
-
21
- class << self; private :portal_options=; end
22
- end
23
-
24
- class_methods do
25
- # Based on +has_many+, but creates a special Portal association
26
- # instead.
27
- #
28
- # Custom options:
29
- #
30
- # * <tt>:portal_key</tt> - The key used for the portal in the FM Data JSON portalData.
31
- # * <tt>:attribute_prefix</tt> - The prefix used for portal attributes in the FM Data JSON.
32
- #
33
- # Example:
34
- #
35
- # has_portal :jobs, portal_key: "JobsTable", attribute_prefix: "Job"
36
- #
37
- def has_portal(name, options = {})
38
- create_association(name, Portal, options)
39
-
40
- # Store options for SpykeFormatter to use if needed
41
- portal_key = options[:portal_key] || name
42
- self.portal_options = portal_options.merge(portal_key.to_s => options.dup.merge(name: name.to_s)).freeze
43
-
44
- define_method "#{name.to_s.singularize}_ids" do
45
- association(name).map(&:id)
46
- end
47
- end
48
- end
49
-
50
- # Override Spyke's association reader to keep a cache of loaded
51
- # portals. Spyke's default behavior is to reload the association
52
- # each time.
53
- #
54
- def association(name)
55
- @loaded_portals ||= {}
56
-
57
- if @loaded_portals.has_key?(name.to_sym)
58
- return @loaded_portals[name.to_sym]
59
- end
60
-
61
- super.tap do |assoc|
62
- next unless assoc.kind_of?(FmRest::Spyke::Portal)
63
- @loaded_portals[name.to_sym] = assoc
64
- end
65
- end
66
-
67
- def reload(*_)
68
- super.tap { @loaded_portals = nil }
69
- end
70
-
71
- def portals
72
- self.class.associations.each_with_object([]) do |(key, _), portals|
73
- candidate = association(key)
74
- next unless candidate.kind_of?(FmRest::Spyke::Portal)
75
- portals << candidate
76
- end
77
- end
78
- end
79
- end
80
- end
81
- end
82
-
@@ -1,171 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/spyke/model/orm"
4
-
5
- module FmRest
6
- module Spyke
7
- module Model
8
- module Attributes
9
- extend ::ActiveSupport::Concern
10
-
11
- include Orm # Needed to extend custom save and reload
12
-
13
- include ::ActiveModel::Dirty
14
- include ::ActiveModel::ForbiddenAttributesProtection
15
-
16
- included do
17
- # Prevent the creation of plain (no prefix/suffix) attribute methods
18
- # when calling ActiveModels' define_attribute_method, otherwise it
19
- # will define an `attribute` method which overrides the one provided
20
- # by Spyke
21
- self.attribute_method_matchers.shift
22
-
23
- # ActiveModel::Dirty methods for id
24
- define_attribute_method(:id)
25
-
26
- # Keep track of attribute mappings so we can get the FM field names
27
- # for changed attributes
28
- class_attribute :mapped_attributes, instance_writer: false, instance_predicate: false
29
-
30
- # class_attribute supports a :default option since ActiveSupport 5.2,
31
- # but we want to support previous versions too so we set the default
32
- # manually instead
33
- self.mapped_attributes = ::ActiveSupport::HashWithIndifferentAccess.new.freeze
34
-
35
- class << self; private :mapped_attributes=; end
36
- end
37
-
38
- class_methods do
39
- # Similar to Spyke::Base.attributes, but allows defining attribute
40
- # methods that map to FM attributes with different names.
41
- #
42
- # Example:
43
- #
44
- # class Person < Spyke::Base
45
- # include FmRest::Spyke::Model
46
- #
47
- # attributes first_name: "FstName", last_name: "LstName"
48
- # end
49
- #
50
- # p = Person.new
51
- # p.first_name = "Jojo"
52
- # p.attributes # => { "FstName" => "Jojo" }
53
- #
54
- def attributes(*attrs)
55
- if attrs.length == 1 && attrs.first.kind_of?(Hash)
56
- attrs.first.each { |from, to| _fmrest_define_attribute(from, to) }
57
- else
58
- attrs.each { |attr| _fmrest_define_attribute(attr, attr) }
59
- end
60
- end
61
-
62
- private
63
-
64
- # Override Spyke::Base.new_or_return (private), called whenever
65
- # loading records from the HTTP API, so we can reset dirty info on
66
- # freshly loaded records
67
- #
68
- # See: https://github.com/balvig/spyke/blob/master/lib/spyke/http.rb
69
- #
70
- def new_or_return(attributes_or_object, *_)
71
- # In case of an existing Spyke object return it as is so that we
72
- # don't accidentally remove dirty data from associations
73
- return super if attributes_or_object.is_a?(::Spyke::Base)
74
- super.tap do |record|
75
- # In ActiveModel 4.x #clear_changes_information is a private
76
- # method, so we need to call it with send() in that case, but
77
- # keep calling it normally for AM5+
78
- if record.respond_to?(:clear_changes_information)
79
- record.clear_changes_information
80
- else
81
- record.send(:clear_changes_information)
82
- end
83
- end
84
- end
85
-
86
- def _fmrest_attribute_methods_container
87
- @fmrest_attribute_methods_container ||= Module.new.tap { |mod| include mod }
88
- end
89
-
90
- def _fmrest_define_attribute(from, to)
91
- raise ArgumentError, "attribute name `id' is reserved for the recordId" if from.to_s == "id"
92
-
93
- # We use a setter here instead of injecting the hash key/value pair
94
- # directly with #[]= so that we don't change the mapped_attributes
95
- # hash on the parent class. The resulting hash is frozen for the
96
- # same reason.
97
- self.mapped_attributes = mapped_attributes.merge(from => to).freeze
98
-
99
- _fmrest_attribute_methods_container.module_eval do
100
- define_method(from) do
101
- attribute(to)
102
- end
103
-
104
- define_method(:"#{from}=") do |value|
105
- send("#{from}_will_change!") unless value == send(from)
106
- set_attribute(to, value)
107
- end
108
- end
109
-
110
- # Define ActiveModel::Dirty's methods
111
- define_attribute_method(from)
112
- end
113
- end
114
-
115
- def id=(value)
116
- id_will_change! unless value == id
117
- super
118
- end
119
-
120
- def reload(*args)
121
- super.tap { |r| clear_changes_information }
122
- end
123
-
124
- def save(*args)
125
- super.tap { |r| changes_applied_after_save if r }
126
- end
127
-
128
- # ActiveModel::Dirty since version 5.2 assumes that if there's an
129
- # @attributes instance variable set we must be using ActiveRecord, so
130
- # we override the instance variable name used by Spyke to avoid issues.
131
- #
132
- # TODO: Submit a pull request to Spyke so this isn't needed
133
- #
134
- def attributes
135
- @_spyke_attributes
136
- end
137
-
138
- # In addition to the comments above on `attributes`, this also adds
139
- # support for forbidden attributes
140
- #
141
- def attributes=(new_attributes)
142
- @_spyke_attributes ||= ::Spyke::Attributes.new(scope.params)
143
- use_setters(sanitize_for_mass_assignment(new_attributes)) if new_attributes && !new_attributes.empty?
144
- end
145
-
146
- private
147
-
148
- def changed_params
149
- attributes.to_params.slice(*mapped_changed)
150
- end
151
-
152
- def mapped_changed
153
- mapped_attributes.values_at(*changed)
154
- end
155
-
156
- # Use known mapped_attributes for inspect
157
- #
158
- def inspect_attributes
159
- mapped_attributes.except(primary_key).map do |k, v|
160
- "#{k}: #{attribute(v).inspect}"
161
- end.join(', ')
162
- end
163
-
164
- def changes_applied_after_save
165
- changes_applied
166
- portals.each(&:parent_changes_applied)
167
- end
168
- end
169
- end
170
- end
171
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module Spyke
5
- module Model
6
- module Auth
7
- extend ::ActiveSupport::Concern
8
-
9
- class_methods do
10
- # Logs out the database session for this model (and other models
11
- # using the same credentials).
12
- #
13
- # @raise [FmRest::V1::TokenSession::NoSessionTokenSet] if no session
14
- # token was set (and no request is sent).
15
- def logout!
16
- connection.delete(FmRest::V1.session_path("dummy-token"))
17
- end
18
-
19
- # Logs out the database session for this model (and other models
20
- # using the same credentials). Unlike `logout!`, no exception is
21
- # raised in case of missing session token.
22
- #
23
- # @return [Boolean] Whether the logout request was sent (it's only
24
- # sent if a session token was previously set)
25
- def logout
26
- logout!
27
- true
28
- rescue FmRest::V1::TokenSession::NoSessionTokenSet
29
- false
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module Spyke
5
- module Model
6
- module Connection
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- class_attribute :fmrest_config, instance_writer: false, instance_predicate: false
11
-
12
- # Overrides the fmrest_config reader created by class_attribute so we
13
- # can default set the default at call time.
14
- #
15
- # This method gets overwriten in subclasses if self.fmrest_config= is
16
- # called.
17
- define_singleton_method(:fmrest_config) do
18
- FmRest.default_connection_settings
19
- end
20
-
21
- class_attribute :faraday_block, instance_accessor: false, instance_predicate: false
22
- class << self; private :faraday_block, :faraday_block=; end
23
-
24
- # FM Data API expects PATCH for updates (Spyke's default was PUT)
25
- self.callback_methods = { create: :post, update: :patch }.freeze
26
- end
27
-
28
- class_methods do
29
- def connection
30
- super || fmrest_connection
31
- end
32
-
33
- # Sets a block for injecting custom middleware into the Faraday
34
- # connection. Example usage:
35
- #
36
- # class MyModel < FmRest::Spyke::Base
37
- # faraday do |conn|
38
- # # Set up a custom logger for the model
39
- # conn.response :logger, MyApp.logger, bodies: true
40
- # end
41
- # end
42
- #
43
- def faraday(&block)
44
- self.faraday_block = block
45
- end
46
-
47
- private
48
-
49
- def fmrest_connection
50
- @fmrest_connection ||=
51
- begin
52
- config = fmrest_config
53
-
54
- FmRest::V1.build_connection(config) do |conn|
55
- faraday_block.call(conn) if faraday_block
56
-
57
- # Pass the class to SpykeFormatter's initializer so it can have
58
- # access to extra context defined in the model, e.g. a portal
59
- # where name of the portal and the attributes prefix don't match
60
- # and need to be specified as options to `portal`
61
- conn.use FmRest::Spyke::SpykeFormatter, self
62
-
63
- conn.use FmRest::V1::TypeCoercer, config
64
-
65
- # FmRest::Spyke::JsonParse expects symbol keys
66
- conn.response :json, parser_options: { symbolize_names: true }
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
74
- end