fmrest 0.10.1 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +36 -0
  4. data/README.md +193 -761
  5. metadata +71 -98
  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 -91
  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