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.
- checksums.yaml +4 -4
- data/.yardopts +2 -0
- data/CHANGELOG.md +38 -0
- data/README.md +194 -763
- metadata +70 -97
- data/.gitignore +0 -26
- data/.rspec +0 -3
- data/.travis.yml +0 -5
- data/Gemfile +0 -3
- data/Rakefile +0 -6
- data/fmrest.gemspec +0 -38
- data/lib/fmrest.rb +0 -29
- data/lib/fmrest/errors.rb +0 -28
- data/lib/fmrest/spyke.rb +0 -21
- data/lib/fmrest/spyke/base.rb +0 -23
- data/lib/fmrest/spyke/container_field.rb +0 -59
- data/lib/fmrest/spyke/model.rb +0 -36
- data/lib/fmrest/spyke/model/associations.rb +0 -82
- data/lib/fmrest/spyke/model/attributes.rb +0 -171
- data/lib/fmrest/spyke/model/auth.rb +0 -35
- data/lib/fmrest/spyke/model/connection.rb +0 -74
- data/lib/fmrest/spyke/model/container_fields.rb +0 -25
- data/lib/fmrest/spyke/model/global_fields.rb +0 -40
- data/lib/fmrest/spyke/model/http.rb +0 -37
- data/lib/fmrest/spyke/model/orm.rb +0 -212
- data/lib/fmrest/spyke/model/serialization.rb +0 -91
- data/lib/fmrest/spyke/model/uri.rb +0 -30
- data/lib/fmrest/spyke/portal.rb +0 -55
- data/lib/fmrest/spyke/relation.rb +0 -359
- data/lib/fmrest/spyke/spyke_formatter.rb +0 -273
- data/lib/fmrest/spyke/validation_error.rb +0 -25
- data/lib/fmrest/string_date.rb +0 -220
- data/lib/fmrest/token_store.rb +0 -6
- data/lib/fmrest/token_store/active_record.rb +0 -74
- data/lib/fmrest/token_store/base.rb +0 -25
- data/lib/fmrest/token_store/memory.rb +0 -26
- data/lib/fmrest/token_store/moneta.rb +0 -41
- data/lib/fmrest/token_store/redis.rb +0 -45
- data/lib/fmrest/v1.rb +0 -21
- data/lib/fmrest/v1/connection.rb +0 -89
- data/lib/fmrest/v1/container_fields.rb +0 -114
- data/lib/fmrest/v1/dates.rb +0 -81
- data/lib/fmrest/v1/paths.rb +0 -47
- data/lib/fmrest/v1/raise_errors.rb +0 -57
- data/lib/fmrest/v1/token_session.rb +0 -142
- data/lib/fmrest/v1/token_store/active_record.rb +0 -13
- data/lib/fmrest/v1/token_store/memory.rb +0 -13
- data/lib/fmrest/v1/type_coercer.rb +0 -192
- data/lib/fmrest/v1/utils.rb +0 -95
- data/lib/fmrest/version.rb +0 -5
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module FmRest
|
4
|
-
module Spyke
|
5
|
-
# ActiveModel 4 doesn't include a ValidationError class, which we want to
|
6
|
-
# raise when model.validate! fails.
|
7
|
-
#
|
8
|
-
# In order to break the least amount of code that uses AM5+, while still
|
9
|
-
# supporting AM4 we use this proxy class that inherits from
|
10
|
-
# AM::ValidationError if it's there, or reimplements it otherwise
|
11
|
-
if defined?(::ActiveModel::ValidationError)
|
12
|
-
class ValidationError < ::ActiveModel::ValidationError; end
|
13
|
-
else
|
14
|
-
class ValidationError < StandardError
|
15
|
-
attr_reader :model
|
16
|
-
|
17
|
-
def initialize(model)
|
18
|
-
@model = model
|
19
|
-
errors = @model.errors.full_messages.join(", ")
|
20
|
-
super("Invalid model: #{errors}")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/fmrest/string_date.rb
DELETED
@@ -1,220 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "date"
|
4
|
-
|
5
|
-
module FmRest
|
6
|
-
# Gotchas:
|
7
|
-
#
|
8
|
-
# 1.
|
9
|
-
#
|
10
|
-
# Date === <StringDate instance> # => false
|
11
|
-
#
|
12
|
-
# The above can affect case conditions, as trying to match a StringDate
|
13
|
-
# with:
|
14
|
-
#
|
15
|
-
# case obj
|
16
|
-
# when Date
|
17
|
-
# ...
|
18
|
-
#
|
19
|
-
# ...will not work.
|
20
|
-
#
|
21
|
-
# Instead one must specify the FmRest::StringDate class:
|
22
|
-
#
|
23
|
-
# case obj
|
24
|
-
# when Date, FmRest::StringDate
|
25
|
-
# ...
|
26
|
-
#
|
27
|
-
# 2.
|
28
|
-
#
|
29
|
-
# StringDate#eql? only matches other strings, not dates.
|
30
|
-
#
|
31
|
-
# This could affect hash indexing when a StringDate is used as a key.
|
32
|
-
#
|
33
|
-
# TODO: Verify the above
|
34
|
-
#
|
35
|
-
# 3.
|
36
|
-
#
|
37
|
-
# StringDate#succ and StringDate#next return a String, despite Date#succ
|
38
|
-
# and Date#next also existing.
|
39
|
-
#
|
40
|
-
# Workaround: Use StringDate#next_day or strdate + 1
|
41
|
-
#
|
42
|
-
# 4.
|
43
|
-
#
|
44
|
-
# StringDate#to_s returns the original string, not the Date string
|
45
|
-
# representation.
|
46
|
-
#
|
47
|
-
# Workaround: Use strdate.to_date.to_s
|
48
|
-
#
|
49
|
-
# 5.
|
50
|
-
#
|
51
|
-
# StringDate#hash returns the hash for the string (important when using
|
52
|
-
# a StringDate as a hash key)
|
53
|
-
#
|
54
|
-
# 6.
|
55
|
-
#
|
56
|
-
# StringDate#as_json returns the string
|
57
|
-
#
|
58
|
-
# Workaround: Use strdate.to_date.as_json
|
59
|
-
#
|
60
|
-
# 7.
|
61
|
-
#
|
62
|
-
# Equality with Date is not reciprocal:
|
63
|
-
#
|
64
|
-
# str_date == date #=> true
|
65
|
-
# date == str_date #=> false
|
66
|
-
#
|
67
|
-
# NOTE: Potential workaround: Inherit StringDate from Date instead of String
|
68
|
-
#
|
69
|
-
# 8.
|
70
|
-
#
|
71
|
-
# Calling string transforming methods (e.g. .upcase) returns a StringDate
|
72
|
-
# instead of a String.
|
73
|
-
#
|
74
|
-
# NOTE: Potential workaround: Inherit StringDate from Date instead of String
|
75
|
-
#
|
76
|
-
class StringDate < String
|
77
|
-
DELEGATE_CLASS = ::Date
|
78
|
-
|
79
|
-
class InvalidDate < ArgumentError; end
|
80
|
-
|
81
|
-
class << self
|
82
|
-
def strptime(str, date_format, *_)
|
83
|
-
begin
|
84
|
-
date = self::DELEGATE_CLASS.strptime(str, date_format)
|
85
|
-
rescue ArgumentError
|
86
|
-
raise InvalidDate
|
87
|
-
end
|
88
|
-
|
89
|
-
new(str, date)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def initialize(str, date, **str_args)
|
94
|
-
raise ArgumentError, "str must be of class String" unless str.is_a?(String)
|
95
|
-
raise ArgumentError, "date must be of class #{self.class::DELEGATE_CLASS.name}" unless date.is_a?(self.class::DELEGATE_CLASS)
|
96
|
-
|
97
|
-
super(str, **str_args)
|
98
|
-
|
99
|
-
@delegate = date
|
100
|
-
|
101
|
-
freeze
|
102
|
-
end
|
103
|
-
|
104
|
-
def is_a?(klass)
|
105
|
-
klass == ::Date || super
|
106
|
-
end
|
107
|
-
alias_method :kind_of?, :is_a?
|
108
|
-
|
109
|
-
def to_date
|
110
|
-
@delegate
|
111
|
-
end
|
112
|
-
|
113
|
-
def to_datetime
|
114
|
-
@delegate.to_datetime
|
115
|
-
end
|
116
|
-
|
117
|
-
def to_time
|
118
|
-
@delegate.to_time
|
119
|
-
end
|
120
|
-
|
121
|
-
# ActiveSupport method
|
122
|
-
def in_time_zone(*_)
|
123
|
-
@delegate.in_time_zone(*_)
|
124
|
-
end
|
125
|
-
|
126
|
-
def inspect
|
127
|
-
"#<#{self.class.name} #{@delegate.inspect} - #{super}>"
|
128
|
-
end
|
129
|
-
|
130
|
-
def <=>(oth)
|
131
|
-
return @delegate <=> oth if oth.is_a?(::Date) || oth.is_a?(Numeric)
|
132
|
-
super
|
133
|
-
end
|
134
|
-
|
135
|
-
def +(val)
|
136
|
-
return @delegate + val if val.kind_of?(Numeric)
|
137
|
-
super
|
138
|
-
end
|
139
|
-
|
140
|
-
def <<(val)
|
141
|
-
return @delegate << val if val.kind_of?(Numeric)
|
142
|
-
super
|
143
|
-
end
|
144
|
-
|
145
|
-
def ==(oth)
|
146
|
-
return @delegate == oth if oth.kind_of?(::Date) || oth.kind_of?(Numeric)
|
147
|
-
super
|
148
|
-
end
|
149
|
-
alias_method :===, :==
|
150
|
-
|
151
|
-
def upto(oth, &blk)
|
152
|
-
return @delegate.upto(oth, &blk) if oth.kind_of?(::Date) || oth.kind_of?(Numeric)
|
153
|
-
super
|
154
|
-
end
|
155
|
-
|
156
|
-
def between?(a, b)
|
157
|
-
return @delegate.between?(a, b) if [a, b].any? {|o| o.is_a?(::Date) || o.is_a?(Numeric) }
|
158
|
-
super
|
159
|
-
end
|
160
|
-
|
161
|
-
private
|
162
|
-
|
163
|
-
def respond_to_missing?(name, include_private = false)
|
164
|
-
@delegate.respond_to?(name, include_private)
|
165
|
-
end
|
166
|
-
|
167
|
-
def method_missing(method, *args, &block)
|
168
|
-
@delegate.send(method, *args, &block)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
class StringDateTime < StringDate
|
173
|
-
DELEGATE_CLASS = ::DateTime
|
174
|
-
|
175
|
-
def is_a?(klass)
|
176
|
-
klass == ::DateTime || super
|
177
|
-
end
|
178
|
-
alias_method :kind_of?, :is_a?
|
179
|
-
|
180
|
-
def to_date
|
181
|
-
@delegate.to_date
|
182
|
-
end
|
183
|
-
|
184
|
-
def to_datetime
|
185
|
-
@delegate
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
module StringDateAwareness
|
190
|
-
def _parse(v, *_)
|
191
|
-
if v.is_a?(StringDateTime)
|
192
|
-
return { year: v.year, mon: v.month, mday: v.mday, hour: v.hour, min: v.min, sec: v.sec, sec_fraction: v.sec_fraction, offset: v.offset }
|
193
|
-
end
|
194
|
-
if v.is_a?(StringDate)
|
195
|
-
return { year: v.year, mon: v.month, mday: v.mday }
|
196
|
-
end
|
197
|
-
super
|
198
|
-
end
|
199
|
-
|
200
|
-
def parse(v, *_)
|
201
|
-
if v.is_a?(StringDate)
|
202
|
-
return self == ::DateTime ? v.to_datetime : v.to_date
|
203
|
-
end
|
204
|
-
super
|
205
|
-
end
|
206
|
-
|
207
|
-
# Overriding case equality method so that it returns true for
|
208
|
-
# `FmRest::StringDate` instances
|
209
|
-
#
|
210
|
-
# Calls superclass method
|
211
|
-
#
|
212
|
-
def ===(other)
|
213
|
-
super || other.is_a?(StringDate)
|
214
|
-
end
|
215
|
-
|
216
|
-
def self.enable(classes: [Date, DateTime])
|
217
|
-
classes.each { |klass| klass.singleton_class.prepend(self) }
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
data/lib/fmrest/token_store.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "fmrest/token_store/base"
|
4
|
-
require "active_record"
|
5
|
-
|
6
|
-
module FmRest
|
7
|
-
module TokenStore
|
8
|
-
# Heavily inspired by Moneta's ActiveRecord store:
|
9
|
-
#
|
10
|
-
# https://github.com/minad/moneta/blob/master/lib/moneta/adapters/activerecord.rb
|
11
|
-
#
|
12
|
-
class ActiveRecord < Base
|
13
|
-
DEFAULT_TABLE_NAME = "fmrest_session_tokens".freeze
|
14
|
-
|
15
|
-
@connection_lock = ::Mutex.new
|
16
|
-
class << self
|
17
|
-
attr_reader :connection_lock
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader :connection_pool, :model
|
21
|
-
|
22
|
-
delegate :with_connection, to: :connection_pool
|
23
|
-
|
24
|
-
def initialize(options = {})
|
25
|
-
super
|
26
|
-
|
27
|
-
@connection_pool = ::ActiveRecord::Base.connection_pool
|
28
|
-
|
29
|
-
create_table
|
30
|
-
|
31
|
-
@model = Class.new(::ActiveRecord::Base)
|
32
|
-
@model.table_name = table_name
|
33
|
-
end
|
34
|
-
|
35
|
-
def delete(key)
|
36
|
-
model.where(scope: key).delete_all
|
37
|
-
end
|
38
|
-
|
39
|
-
def load(key)
|
40
|
-
model.where(scope: key).pluck(:token).first
|
41
|
-
end
|
42
|
-
|
43
|
-
def store(key, value)
|
44
|
-
record = model.find_or_initialize_by(scope: key)
|
45
|
-
record.token = value
|
46
|
-
record.save!
|
47
|
-
value
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def create_table
|
53
|
-
with_connection do |conn|
|
54
|
-
return if conn.table_exists?(table_name)
|
55
|
-
|
56
|
-
# Prevent multiple connections from attempting to create the table simultaneously.
|
57
|
-
self.class.connection_lock.synchronize do
|
58
|
-
conn.create_table(table_name, id: false) do |t|
|
59
|
-
t.string :scope, null: false
|
60
|
-
t.string :token, null: false
|
61
|
-
t.datetime :updated_at
|
62
|
-
end
|
63
|
-
conn.add_index(table_name, :scope, unique: true)
|
64
|
-
conn.add_index(table_name, [:scope, :token])
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def table_name
|
70
|
-
options[:table_name] || DEFAULT_TABLE_NAME
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module FmRest
|
4
|
-
module TokenStore
|
5
|
-
class Base
|
6
|
-
attr_reader :options
|
7
|
-
|
8
|
-
def initialize(options = {})
|
9
|
-
@options = options
|
10
|
-
end
|
11
|
-
|
12
|
-
def load(key)
|
13
|
-
raise "Not implemented"
|
14
|
-
end
|
15
|
-
|
16
|
-
def store(key, value)
|
17
|
-
raise "Not implemented"
|
18
|
-
end
|
19
|
-
|
20
|
-
def delete(key)
|
21
|
-
raise "Not implemented"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "fmrest/token_store/base"
|
4
|
-
|
5
|
-
module FmRest
|
6
|
-
module TokenStore
|
7
|
-
class Memory < Base
|
8
|
-
def initialize(*args)
|
9
|
-
super
|
10
|
-
@tokens = {}
|
11
|
-
end
|
12
|
-
|
13
|
-
def delete(key)
|
14
|
-
@tokens.delete(key)
|
15
|
-
end
|
16
|
-
|
17
|
-
def load(key)
|
18
|
-
@tokens[key]
|
19
|
-
end
|
20
|
-
|
21
|
-
def store(key, value)
|
22
|
-
@tokens[key] = value
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "fmrest/token_store/base"
|
4
|
-
require "moneta"
|
5
|
-
|
6
|
-
module FmRest
|
7
|
-
module TokenStore
|
8
|
-
class Moneta < Base
|
9
|
-
DEFAULT_ADAPTER = :Memory
|
10
|
-
DEFAULT_PREFIX = "fmrest-token:".freeze
|
11
|
-
|
12
|
-
attr_reader :moneta
|
13
|
-
|
14
|
-
# @param options [Hash]
|
15
|
-
# Options to pass to `Moneta.new`
|
16
|
-
# @option options [Symbol] :adapter (:Memory)
|
17
|
-
# The Moneta adapter to use
|
18
|
-
# @option options [String] :prefix (DEFAULT_PREFIX)
|
19
|
-
# The prefix to use for keys
|
20
|
-
def initialize(options = {})
|
21
|
-
options = options.dup
|
22
|
-
super(options)
|
23
|
-
adapter = options.delete(:adapter) || DEFAULT_ADAPTER
|
24
|
-
options[:prefix] ||= DEFAULT_PREFIX
|
25
|
-
@moneta = ::Moneta.new(adapter, options)
|
26
|
-
end
|
27
|
-
|
28
|
-
def load(key)
|
29
|
-
moneta[key]
|
30
|
-
end
|
31
|
-
|
32
|
-
def delete(key)
|
33
|
-
moneta.delete(key)
|
34
|
-
end
|
35
|
-
|
36
|
-
def store(key, value)
|
37
|
-
moneta[key] = value
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "fmrest/token_store/base"
|
4
|
-
require "redis" unless defined?(MockRedis)
|
5
|
-
|
6
|
-
module FmRest
|
7
|
-
module TokenStore
|
8
|
-
class Redis < Base
|
9
|
-
DEFAULT_PREFIX = "fmrest-token:".freeze
|
10
|
-
|
11
|
-
STORE_OPTIONS = [:redis, :prefix].freeze
|
12
|
-
|
13
|
-
def initialize(options = {})
|
14
|
-
super
|
15
|
-
@redis = @options[:redis] || ::Redis.new(options_for_redis)
|
16
|
-
@prefix = @options[:prefix] || DEFAULT_PREFIX
|
17
|
-
end
|
18
|
-
|
19
|
-
def load(key)
|
20
|
-
@redis.get(prefix_key(key))
|
21
|
-
end
|
22
|
-
|
23
|
-
def store(key, value)
|
24
|
-
@redis.set(prefix_key(key), value)
|
25
|
-
value
|
26
|
-
end
|
27
|
-
|
28
|
-
def delete(key)
|
29
|
-
@redis.del(prefix_key(key))
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def options_for_redis
|
35
|
-
@options.dup.tap do |options|
|
36
|
-
STORE_OPTIONS.each { |opt| options.delete(opt) }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def prefix_key(key)
|
41
|
-
"#{@prefix}#{key}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|