filemaker 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
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