filemaker 0.0.18 → 0.0.19

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/README.md +55 -11
  4. data/diagram.svg +1 -0
  5. data/filemaker.gemspec +2 -0
  6. data/lib/filemaker.rb +2 -1
  7. data/lib/filemaker/configuration.rb +1 -1
  8. data/lib/filemaker/layout.rb +1 -1
  9. data/lib/filemaker/metadata/field.rb +6 -3
  10. data/lib/filemaker/model/batches.rb +16 -0
  11. data/lib/filemaker/model/builder.rb +5 -2
  12. data/lib/filemaker/model/components.rb +2 -0
  13. data/lib/filemaker/model/criteria.rb +26 -6
  14. data/lib/filemaker/model/field.rb +11 -2
  15. data/lib/filemaker/model/fields.rb +15 -9
  16. data/lib/filemaker/model/optional.rb +1 -1
  17. data/lib/filemaker/model/pagination.rb +6 -1
  18. data/lib/filemaker/model/persistable.rb +1 -1
  19. data/lib/filemaker/model/relations/proxy.rb +4 -1
  20. data/lib/filemaker/model/selectable.rb +2 -2
  21. data/lib/filemaker/model/types/attachment.rb +102 -0
  22. data/lib/filemaker/model/types/email.rb +41 -0
  23. data/lib/filemaker/record.rb +7 -4
  24. data/lib/filemaker/server.rb +33 -13
  25. data/lib/filemaker/version.rb +1 -1
  26. data/lib/generators/filemaker/model/model_generator.rb +2 -1
  27. data/spec/filemaker/configuration_spec.rb +1 -1
  28. data/spec/filemaker/layout_spec.rb +8 -8
  29. data/spec/filemaker/metadata/field_spec.rb +9 -1
  30. data/spec/filemaker/model/criteria_spec.rb +17 -17
  31. data/spec/filemaker/model/relations_spec.rb +5 -0
  32. data/spec/filemaker/model_spec.rb +66 -1
  33. data/spec/filemaker/resultset_spec.rb +1 -1
  34. data/spec/filemaker/store/database_store_spec.rb +1 -1
  35. data/spec/support/filemaker.yml +2 -2
  36. data/spec/support/models.rb +3 -1
  37. metadata +35 -3
@@ -42,7 +42,7 @@ module Filemaker
42
42
 
43
43
  sort_spec.each do |spec|
44
44
  fieldname, direction = spec.split(' ')
45
- direction = 'asc' unless direction
45
+ direction ||= 'asc'
46
46
 
47
47
  field = klass.find_field_by_name(fieldname)
48
48
 
@@ -5,7 +5,7 @@ module Filemaker
5
5
  def page(value)
6
6
  value = 1 if value.nil?
7
7
  chains << :page
8
- @_page = value.to_i
8
+ @_page = positive_page(value.to_i)
9
9
  update_skip
10
10
  end
11
11
 
@@ -37,6 +37,11 @@ module Filemaker
37
37
  skip(skip) unless skip.zero?
38
38
  self
39
39
  end
40
+
41
+ def positive_page(page)
42
+ return 1 if page.nil? || !page.is_a?(Integer)
43
+ page.positive? ? page : 1
44
+ end
40
45
  end
41
46
  end
42
47
  end
@@ -10,7 +10,7 @@ module Filemaker
10
10
  # Call save! but do not raise error.
11
11
  def save
12
12
  save!
13
- rescue
13
+ rescue StandardError
14
14
  errors.add(:base) << $! # Does this works?
15
15
  nil
16
16
  end
@@ -26,8 +26,11 @@ module Filemaker
26
26
  @class_name.constantize
27
27
  end
28
28
 
29
+ # Rubocop will complain and ask to fallback on `super`, but we won't be
30
+ # able to do that because the target may have method that throw
31
+ # exception
29
32
  def method_missing(name, *args, &block)
30
- target.send(name, *args, &block) || super
33
+ target.send(name, *args, &block)
31
34
  end
32
35
 
33
36
  def respond_to_missing?(method_name, include_private = false)
@@ -56,7 +56,7 @@ module Filemaker
56
56
  first
57
57
  end
58
58
 
59
- %w(eq cn bw ew gt gte lt lte neq).each do |operator|
59
+ %w[eq cn bw ew gt gte lt lte neq].each do |operator|
60
60
  define_method(operator) do |criterion, &block|
61
61
  if chains.include?(:in)
62
62
  raise Filemaker::Errors::MixedClauseError,
@@ -82,7 +82,7 @@ module Filemaker
82
82
 
83
83
  # Inside define_method, we cannot have yield or block_given?, so we
84
84
  # just use &block
85
- block.call(options) if block
85
+ block&.call(options)
86
86
  self
87
87
  end
88
88
  end
@@ -0,0 +1,102 @@
1
+ require 'net/http'
2
+ require 'mimemagic'
3
+
4
+ module Filemaker
5
+ module Model
6
+ module Types
7
+ class Attachment
8
+ attr_reader :_body, :content_type, :extension, :klass
9
+
10
+ def initialize(value, klass)
11
+ @value = value
12
+ @klass = klass
13
+ end
14
+
15
+ def url
16
+ @value.to_s
17
+ end
18
+
19
+ def file_extension
20
+ # We need to use .path to eliminate query string
21
+ File.extname(URI.parse(url).path)
22
+ end
23
+
24
+ def filename
25
+ return if url.blank?
26
+ File.basename(URI.parse(url).path)
27
+ end
28
+
29
+ def body
30
+ return @_body if defined?(@_body)
31
+
32
+ valid_files = %w[
33
+ .pdf
34
+ .jpeg .jpg .png .gif .tif .tiff
35
+ .doc .docx .xls .xlsx .ppt .pptx .pptm
36
+ .txt
37
+ .rar .zip .webarchive
38
+ .htm .html
39
+ .java
40
+ ]
41
+
42
+ @_body = download_protected_file
43
+
44
+ if !file_extension.blank? &&
45
+ valid_files.include?(file_extension.try(:downcase))
46
+
47
+ @content_type = MimeMagic.by_extension(file_extension).try(:type)
48
+ @extension = file_extension
49
+ else
50
+ mime_type = MimeMagic.by_magic(@_body)
51
+
52
+ unless mime_type.blank?
53
+ case mime_type.type.downcase
54
+ when 'application/msword'
55
+ @content_type = 'application/msword'
56
+ @extension = '.doc'
57
+ when 'application/pdf'
58
+ @content_type = 'application/pdf'
59
+ @extension = '.pdf'
60
+ when 'application/x-ole-storage'
61
+ @content_type = 'application/vnd.ms-excel'
62
+ @extension = '.xls'
63
+ when 'application/vnd.ms-excel'
64
+ @content_type = 'application/vnd.ms-excel'
65
+ @extension = '.xls'
66
+ when 'image/jpeg'
67
+ @content_type = 'image/jpeg'
68
+ @extension = '.jpg'
69
+ when 'image/png'
70
+ @content_type = 'image/png'
71
+ @extension = '.png'
72
+ when 'application/vnd.oasis.opendocument.text'
73
+ @content_type = 'application/vnd.oasis.opendocument.text'
74
+ @extension = '.odt'
75
+ else
76
+ # No choice, we have to assign it somehow
77
+ @content_type = mime_type.type
78
+ @extension = MIME::Types[@content_type].first
79
+ .try(:extensions)
80
+ .try(:first)
81
+ @extension = ".#{@extension}" if @extension
82
+ end
83
+ end
84
+ end
85
+
86
+ @_body
87
+ end
88
+
89
+ private
90
+
91
+ def download_protected_file
92
+ req = Net::HTTP::Get.new(url)
93
+ req.basic_auth(klass.server.account_name, klass.server.password)
94
+ res = Net::HTTP.new(klass.server.host, 80)
95
+ res = res.start { |http| http.request(req) }
96
+
97
+ res.body
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,41 @@
1
+ module Filemaker
2
+ module Model
3
+ module Types
4
+ class Email
5
+ def initialize(value)
6
+ # to_s incoming value, this can prevent similar type from
7
+ # nesting deeply
8
+ @value = value.nil? ? nil : value.to_s
9
+ end
10
+
11
+ def value
12
+ email = @value&.strip&.split(%r{,|\(|\/|\s})
13
+ &.reject(&:empty?)&.first&.downcase
14
+ &.gsub(/[\uFF20\uFE6B\u0040]/, '@')
15
+
16
+ email&.include?('@') ? email : nil
17
+ end
18
+
19
+ def value=(v)
20
+ self.value = v
21
+ end
22
+
23
+ def to_s
24
+ value
25
+ end
26
+
27
+ def ==(other)
28
+ to_s == other.to_s
29
+ end
30
+ alias eql? ==
31
+
32
+ # In FileMaker, at-sign is for wildcard query. In order to search for
33
+ # email, we need to escape at-sign. Note the single-quote escaping!
34
+ # e.g. 'a@host.com' will become 'a\\@host.com'
35
+ def to_query
36
+ value.gsub('@', '\@')
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -51,10 +51,13 @@ module Filemaker
51
51
  end
52
52
 
53
53
  def []=(key, value)
54
- return super unless @ready
55
- raise(Filemaker::Errors::InvalidFieldError, "Invalid field: #{key}") \
54
+ if @ready
55
+ raise(Filemaker::Errors::InvalidFieldError, "Invalid field: #{key}") \
56
56
  unless key?(key)
57
- @dirty[key] = value
57
+ @dirty[key] = value
58
+ else
59
+ super
60
+ end
58
61
  end
59
62
 
60
63
  private
@@ -87,7 +90,7 @@ module Filemaker
87
90
  super
88
91
  end
89
92
 
90
- def respond_to_missing?
93
+ def respond_to_missing?(method_name, include_private = false)
91
94
  super
92
95
  end
93
96
  end
@@ -48,11 +48,23 @@ module Filemaker
48
48
  response = @connection.public_send(method, endpoint, params)
49
49
 
50
50
  case response.status
51
- when 200 then [response, params]
52
- when 401 then raise Errors::AuthenticationError, 'Auth failed.'
53
- when 0 then raise Errors::CommunicationError, 'Empty response.'
54
- when 404 then raise Errors::CommunicationError, 'HTTP 404 Not Found'
55
- when 302 then raise Errors::CommunicationError, 'Redirect not supported'
51
+ when 200
52
+ [response, params]
53
+ when 401
54
+ raise Errors::AuthenticationError,
55
+ "[#{response.status}] Authentication failed."
56
+ when 0
57
+ raise Errors::CommunicationError,
58
+ "[#{response.status}] Empty response."
59
+ when 404
60
+ raise Errors::CommunicationError,
61
+ "[#{response.status}] Not found"
62
+ when 302
63
+ raise Errors::CommunicationError,
64
+ "[#{response.status}] Redirect not supported"
65
+ when 502
66
+ raise Errors::CommunicationError,
67
+ "[#{response.status}] Bad gateway. Too many records."
56
68
  else
57
69
  msg = "Unknown response status = #{response.status}"
58
70
  raise Errors::CommunicationError, msg
@@ -70,21 +82,29 @@ module Filemaker
70
82
 
71
83
  Faraday.new(@config.url, faraday_options) do |faraday|
72
84
  faraday.request :url_encoded
73
- faraday.adapter :typhoeus
74
85
  faraday.headers[:user_agent] = \
75
86
  "filemaker-ruby-#{Filemaker::VERSION}".freeze
76
87
  faraday.basic_auth @config.account_name, @config.password
88
+
89
+ # The order of the middleware is important, so adapter must be the last
90
+ faraday.adapter :typhoeus
77
91
  end
78
92
  end
79
93
 
94
+ # {"-db"=>"mydb", "-lay"=>"mylay", "email"=>"a@b.com", "updated_at": Date}
80
95
  def serialize_args(args)
81
96
  return {} if args.nil?
82
97
 
83
98
  args.each do |key, value|
84
99
  case value
85
- when DateTime then args[key] = value.strftime('%m/%d/%Y %H:%M:%S')
86
- when Date then args[key] = value.strftime('%m/%d/%Y')
87
- when Time then args[key] = value.strftime('%H:%M')
100
+ when DateTime
101
+ args[key] = value.strftime('%m/%d/%Y %H:%M:%S')
102
+ when Date
103
+ args[key] = value.strftime('%m/%d/%Y')
104
+ when Time
105
+ args[key] = value.strftime('%H:%M')
106
+ when Filemaker::Model::Types::Email
107
+ args[key] = value.to_query
88
108
  else
89
109
  # Especially for range operator (...), we want to output as String
90
110
  args[key] = value.to_s
@@ -164,10 +184,10 @@ module Filemaker
164
184
 
165
185
  # TODO: Should we convert it to string so 'cURL' will work also?
166
186
  def log_action(params)
167
- case @config.log
168
- when :simple then log_simple(params)
169
- when :curl then log_curl(params)
170
- when :curl_auth then log_curl(params, true)
187
+ case @config.log.to_s
188
+ when 'simple' then log_simple(params)
189
+ when 'curl' then log_curl(params)
190
+ when 'curl_auth' then log_curl(params, true)
171
191
  end
172
192
  end
173
193
 
@@ -1,3 +1,3 @@
1
1
  module Filemaker
2
- VERSION = '0.0.18'.freeze
2
+ VERSION = '0.0.19'.freeze
3
3
  end
@@ -26,7 +26,8 @@ module Filemaker
26
26
  'number' => 'number',
27
27
  'date' => 'date',
28
28
  'time' => 'datetime',
29
- 'timestamp' => 'datetime'
29
+ 'timestamp' => 'datetime',
30
+ 'container' => 'string'
30
31
  }
31
32
 
32
33
  template(
@@ -8,7 +8,7 @@ describe 'Configuration' do
8
8
  expect(Filemaker.registry['default'].account_name).to eq \
9
9
  'FILEMAKER_ACCOUNT_NAME'
10
10
  expect(Filemaker.registry['default'].ssl).to eq({ 'verify' => false })
11
- expect(Filemaker.registry['default'].log).to eq :curl
11
+ expect(Filemaker.registry['default'].log).to eq 'curl'
12
12
  end
13
13
 
14
14
  it 'raises ConfigurationError for wrong environment' do
@@ -46,7 +46,7 @@ describe Filemaker::Layout do
46
46
  it 'allows -max, -skip' do
47
47
  resultset = @layout.findall(
48
48
  max: 5, skip: 10,
49
- sortfield: %w(f1 f2), sortorder: ['descend']
49
+ sortfield: %w[f1 f2], sortorder: ['descend']
50
50
  )
51
51
 
52
52
  expect(resultset.params['-max']).to eq 5
@@ -60,8 +60,8 @@ describe Filemaker::Layout do
60
60
  it 'will not accept more than 9 sortfields' do
61
61
  expect do
62
62
  @layout.findall(
63
- sortfield: %w(f1 f2 f3 f4 f5 f6 f7 f8 f9 f10),
64
- sortorder: %w(o1 o2 o3 o4 o5 o6 o7 o8 o9)
63
+ sortfield: %w[f1 f2 f3 f4 f5 f6 f7 f8 f9 f10],
64
+ sortorder: %w[o1 o2 o3 o4 o5 o6 o7 o8 o9]
65
65
  )
66
66
  end.to raise_error Filemaker::Errors::ParameterError
67
67
  end
@@ -69,8 +69,8 @@ describe Filemaker::Layout do
69
69
  it 'will not accept more than 9 sortorders' do
70
70
  expect do
71
71
  @layout.findall(
72
- sortfield: %w(f1 f2 f3 f4 f5 f6 f7 f8 f9),
73
- sortorder: %w(o1 o2 o3 o4 o5 o6 o7 o8 o9 o10)
72
+ sortfield: %w[f1 f2 f3 f4 f5 f6 f7 f8 f9],
73
+ sortorder: %w[o1 o2 o3 o4 o5 o6 o7 o8 o9 o10]
74
74
  )
75
75
  end.to raise_error Filemaker::Errors::ParameterError
76
76
  end
@@ -174,7 +174,7 @@ describe Filemaker::Layout do
174
174
 
175
175
  describe 'query' do
176
176
  it 'transform {a: [1,2]} to (q0);(q1)' do
177
- resultset = @layout.query(status: %w(open closed))
177
+ resultset = @layout.query(status: %w[open closed])
178
178
  expect(resultset.params['-query']).to eq '(q0);(q1)'
179
179
  end
180
180
 
@@ -205,7 +205,7 @@ describe Filemaker::Layout do
205
205
  end
206
206
 
207
207
  it 'can do -script.prefind.param' do
208
- resultset = @layout.find(1, script_prefind: %w(Unique yes))
208
+ resultset = @layout.find(1, script_prefind: %w[Unique yes])
209
209
  expect(resultset.params['-script.prefind']).to eq 'Unique'
210
210
  expect(resultset.params['-script.prefind.param']).to eq 'yes'
211
211
  end
@@ -216,7 +216,7 @@ describe Filemaker::Layout do
216
216
  end
217
217
 
218
218
  it 'can do -script.presort.param' do
219
- resultset = @layout.find(1, script_presort: %w(Order ascend))
219
+ resultset = @layout.find(1, script_presort: %w[Order ascend])
220
220
  expect(resultset.params['-script.presort']).to eq 'Order'
221
221
  expect(resultset.params['-script.presort.param']).to eq 'ascend'
222
222
  end
@@ -1,9 +1,10 @@
1
1
  describe Filemaker::Metadata::Field do
2
2
  let(:server) do
3
3
  Filemaker::Server.new do |config|
4
- config.host = 'https://host'
4
+ config.host = 'host'
5
5
  config.account_name = 'account_name'
6
6
  config.password = 'password'
7
+ config.ssl = { verify: false }
7
8
  end
8
9
  end
9
10
  let(:xml) { import_xml_as_string('portal.xml') }
@@ -69,5 +70,12 @@ describe Filemaker::Metadata::Field do
69
70
  expect(field.coerce('/fmi/xml/cnt/1234jpg').to_s).to eq \
70
71
  'https://host/fmi/xml/cnt/1234jpg'
71
72
  end
73
+
74
+ it 'converts container with existing http' do
75
+ allow(field).to receive(:data_type).and_return 'container'
76
+ expect(field.coerce('http://host/fmi/xml/cnt/1234jpg')).to be_a URI
77
+ expect(field.coerce('http://host/fmi/xml/cnt/1234jpg').to_s).to eq \
78
+ 'http://host/fmi/xml/cnt/1234jpg'
79
+ end
72
80
  end
73
81
  end
@@ -6,7 +6,7 @@ describe Filemaker::Model::Criteria do
6
6
  describe 'where' do
7
7
  it 'raises MixedClauseError if mixed with -findquery' do
8
8
  expect do
9
- criteria.in(status: %w(pending subscribed)).where(name: 'Bob')
9
+ criteria.in(status: %w[pending subscribed]).where(name: 'Bob')
10
10
  end.to raise_error Filemaker::Errors::MixedClauseError
11
11
  end
12
12
 
@@ -85,7 +85,7 @@ describe Filemaker::Model::Criteria do
85
85
  context 'comparison operators' do
86
86
  it 'only works on `where` query' do
87
87
  expect do
88
- criteria.in(status: %w(pending subscribed)).eq(name: 'Bob')
88
+ criteria.in(status: %w[pending subscribed]).eq(name: 'Bob')
89
89
  end.to raise_error Filemaker::Errors::MixedClauseError
90
90
  end
91
91
 
@@ -121,32 +121,32 @@ describe Filemaker::Model::Criteria do
121
121
  describe 'in' do
122
122
  it 'raises MixedClauseError if mixed with -find' do
123
123
  expect do
124
- criteria.where(name: 'Bob').in(status: %w(pending subscribed))
124
+ criteria.where(name: 'Bob').in(status: %w[pending subscribed])
125
125
  end.to raise_error Filemaker::Errors::MixedClauseError
126
126
  end
127
127
 
128
128
  it '{a: [1, 2]} to (q0);(q1)' do
129
- criteria.in(name: %w(Bob Lee))
129
+ criteria.in(name: %w[Bob Lee])
130
130
  compound_find = cf.new(criteria.selector)
131
131
  expect(compound_find.key_maps_string).to eq '(q0);(q1)'
132
- expect(criteria.selector).to eq [{ 'name' => %w(Bob Lee) }]
132
+ expect(criteria.selector).to eq [{ 'name' => %w[Bob Lee] }]
133
133
  end
134
134
 
135
135
  it '{a: [1, 2], b: [3, 4]} to (q0,q2);(q0,q3);(q1,q2);(q1,q3)' do
136
- criteria.in(name: %w(Bob Lee), age: ['20', 30])
136
+ criteria.in(name: %w[Bob Lee], age: ['20', 30])
137
137
  compound_find = cf.new(criteria.selector)
138
138
  expect(compound_find.key_maps_string).to eq \
139
139
  '(q0,q2);(q0,q3);(q1,q2);(q1,q3)'
140
140
  expect(criteria.selector).to eq \
141
- [{ 'name' => %w(Bob Lee), 'passage of time' => [20, 30] }]
141
+ [{ 'name' => %w[Bob Lee], 'passage of time' => [20, 30] }]
142
142
  end
143
143
 
144
144
  it '{a: [1, 2], b: 3} to (q0,q2);(q1,q2)' do
145
- criteria.in(name: %w(Bob Lee), age: '30')
145
+ criteria.in(name: %w[Bob Lee], age: '30')
146
146
  compound_find = cf.new(criteria.selector)
147
147
  expect(compound_find.key_maps_string).to eq '(q0,q2);(q1,q2)'
148
148
  expect(criteria.selector).to eq \
149
- [{ 'name' => %w(Bob Lee), 'passage of time' => 30 }]
149
+ [{ 'name' => %w[Bob Lee], 'passage of time' => 30 }]
150
150
  end
151
151
 
152
152
  it '{a: 1, b: 2} to (q0,q1)' do
@@ -166,11 +166,11 @@ describe Filemaker::Model::Criteria do
166
166
  end
167
167
 
168
168
  it '[{a: [1, 2]}, {b: [1, 2]}] to (q0);(q1);(q2);(q3)' do
169
- criteria.in([{ name: %w(Bob Lee) }, { age: [20, 30] }])
169
+ criteria.in([{ name: %w[Bob Lee] }, { age: [20, 30] }])
170
170
  compound_find = cf.new(criteria.selector)
171
171
  expect(compound_find.key_maps_string).to eq '(q0);(q1);(q2);(q3)'
172
172
  expect(criteria.selector).to eq \
173
- [{ 'name' => %w(Bob Lee) }, { 'passage of time' => [20, 30] }]
173
+ [{ 'name' => %w[Bob Lee] }, { 'passage of time' => [20, 30] }]
174
174
  end
175
175
 
176
176
  it '[{a: 1}, {b: 2}] to (q0);(q1)' do
@@ -200,20 +200,20 @@ describe Filemaker::Model::Criteria do
200
200
 
201
201
  describe 'not_in' do
202
202
  it '{a: [1, 2]} to !(q0);!(q1)' do
203
- criteria.not_in(name: %w(Bob Lee))
203
+ criteria.not_in(name: %w[Bob Lee])
204
204
  compound_find = cf.new(criteria.selector)
205
205
  expect(compound_find.key_maps_string).to eq '!(q0);!(q1)'
206
206
  end
207
207
 
208
208
  it '{a: [1, 2], b: [3, 4]} to !(q0,q2);!(q0,q3);!(q1,q2);!(q1,q3)' do
209
- criteria.not_in(name: %w(Bob Lee), age: ['20', 30])
209
+ criteria.not_in(name: %w[Bob Lee], age: ['20', 30])
210
210
  compound_find = cf.new(criteria.selector)
211
211
  expect(compound_find.key_maps_string).to eq \
212
212
  '!(q0,q2);!(q0,q3);!(q1,q2);!(q1,q3)'
213
213
  end
214
214
 
215
215
  it '{a: [1, 2], b: 3} to !(q0,q2);!(q1,q2)' do
216
- criteria.not_in(name: %w(Bob Lee), age: '30')
216
+ criteria.not_in(name: %w[Bob Lee], age: '30')
217
217
  compound_find = cf.new(criteria.selector)
218
218
  expect(compound_find.key_maps_string).to eq '!(q0,q2);!(q1,q2)'
219
219
  end
@@ -231,7 +231,7 @@ describe Filemaker::Model::Criteria do
231
231
  end
232
232
 
233
233
  it '[{a: [1, 2]}, {b: [1, 2]}] to !(q0);!(q1);!(q2);!(q3)' do
234
- criteria.not_in([{ name: %w(Bob Lee) }, { age: [20, 30] }])
234
+ criteria.not_in([{ name: %w[Bob Lee] }, { age: [20, 30] }])
235
235
  compound_find = cf.new(criteria.selector)
236
236
  expect(compound_find.key_maps_string).to eq '!(q0);!(q1);!(q2);!(q3)'
237
237
  end
@@ -255,7 +255,7 @@ describe Filemaker::Model::Criteria do
255
255
  end
256
256
 
257
257
  it 'using in and not_in at the same time' do
258
- criteria.in(name: %w(Bob Lee)).not_in(age: 20, email: 'A')
258
+ criteria.in(name: %w[Bob Lee]).not_in(age: 20, email: 'A')
259
259
  compound_find = cf.new(criteria.selector)
260
260
  expect(compound_find.key_maps_string).to eq '(q0);(q1);!(q2,q3)'
261
261
  end
@@ -297,7 +297,7 @@ describe Filemaker::Model::Criteria do
297
297
 
298
298
  it 'will default to asc for missing order' do
299
299
  criteria.order('name, email')
300
- expect(criteria.options[:sortorder]).to eq %w(ascend ascend)
300
+ expect(criteria.options[:sortorder]).to eq %w[ascend ascend]
301
301
  end
302
302
 
303
303
  it 'will use real FileMaker fieldname' do