dm-filemaker-adapter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTEzN2JmZDA1YjA0Yzg0ZjcxMjllNDkxZDQxM2E4NTE0NzhjYzEwZA==
5
+ data.tar.gz: !binary |-
6
+ YmI3MzhmYWEyODk0MjYwNzNlOTI0NGNhYTJhMWFiYjU1MjA4YjM4OA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NjBiZTQxMmFiOWEzYmMxYWUwNzkxOTcyM2QzNThlMDgyMGJjMDA1OTNmYWNi
10
+ OGU0MmM2YTI4Yzc0Y2YxMDI2MGVmMDRiZGEwYTUyYzYzMjMwOGFiYzU2ZTAz
11
+ M2JhNzRmODE0ZjkwZGM4ZDBhZGIxNTM4YzIwYzNhNzEwM2VjZDk=
12
+ data.tar.gz: !binary |-
13
+ MTRjNDRhYWM3NzkxMjkzNTkwOGQ1N2M0ZmNiYzdkYWU0NGJhMDMyZTc3Njgx
14
+ MmQzYzNlODE2M2UzMWFlOWQ4Y2M0OTYzOTA4NWI0OGZkNTQ2YTdkZjZlMGE1
15
+ MDllNzgxMDBhNzMxMzc0ZTNkM2U3MTg2NjQzNmQ4Mzk0N2I5ODM=
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor/
16
+ todo.txt
17
+ .DS_Store
18
+
19
+ .travis.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+
6
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 wbr
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # dm-filemaker-adapter
2
+
3
+ A Filemaker adapter for DataMapper, allowing DataMapper to use Filemaker Server as a datastore.
4
+
5
+ dm-filemaker-adapter uses the ginjo-rfm gem as the backend command and xml parser. Ginjo-rfm is a full featured filemaker-ruby adapter that exposes most of Filemaker's xml interface functionality in ruby. dm-filemaker-adapter doesn't tap into all of rfm's features, but rather, it provides DataMapper the ability to use Filemaker Server as a backend datastore. All of the basic functionality of DataMapper's CRUD interface is supported, including compound queries and OR queries (using Filemaker's -findquery command), query operators like :field.gt=>..., lazy-loading where possible, first & last record, aggregate queries, ranges, field mapping, and more.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'dm-filemaker-adapter'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dm-filemaker-adapter
20
+
21
+ ## Usage
22
+
23
+ DB_CONFIG = {
24
+ adapter: 'filemaker',
25
+ host: 'my.server.com',
26
+ account_name: 'my-user-name',
27
+ password: 'xxxxxxxxxx',
28
+ database: 'db-name'
29
+ }
30
+
31
+ DataMapper.setup(:default, DB_CONFIG)
32
+
33
+ class User
34
+ include DataMapper::Resource
35
+ storage_names[:default] = 'user_xml' # This is your filemaker layout for the user table.
36
+
37
+ # Property & field names in this list must be lowercase, regardless of what they are in Filemaker.
38
+
39
+ property :userid, String, :key=>true, :required=>false
40
+ property :email, String
41
+ property :login, String, :field=>'username'
42
+ property :updated, DateTime, :field=>'updated_at'
43
+ property :encrypted_password, BCryptPassword
44
+ end
45
+
46
+ DataMapper.finalize
47
+
48
+ User.get 'usr1035'
49
+ User.first :email => 'wbr'
50
+ User.all :updated.gt => 3.days.ago
51
+
52
+
53
+
54
+
55
+
56
+
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ require "bundler/gem_tasks"
5
+ require "rspec/core/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
10
+
11
+ desc "version"
12
+ task :version do
13
+ require 'dm-filemaker-adapter/version'
14
+ p DataMapper::FilemakerAdapter::VERSION
15
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dm-filemaker-adapter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dm-filemaker-adapter"
8
+ spec.version = DataMapper::FilemakerAdapter::VERSION
9
+ spec.authors = ["William Richardson"]
10
+ spec.email = ["https://github.com/ginjo/dm-filemaker-adapter"]
11
+ spec.summary = %q{Filemaker adapter for DataMapper}
12
+ spec.description = %q{Use Filemaker Server as a datastore for DataMapper ORM}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "data_mapper"
22
+ spec.add_dependency "ginjo-rfm"
23
+
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,320 @@
1
+ # Property & field names in dm-filemaker-adapter models must be declared lowercase, regardless of what they are in FMP.
2
+
3
+ module DataMapper
4
+ [Resource, Model, Adapters]
5
+
6
+ # All this to tack on class and instance methods to the model/resource.
7
+ module Resource
8
+ class << self
9
+ alias_method :included_orig, :included
10
+ def included(klass)
11
+ included_orig(klass)
12
+ if klass.repository.adapter.to_s[/filemaker/i]
13
+ klass.instance_eval do
14
+ extend repository.adapter.class::ModelMethods
15
+ include repository.adapter.class::ResourceMethods
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module Model
23
+ #attr_accessor :last_query
24
+ alias_method :finalize_orig, :finalize
25
+ def finalize(*args)
26
+ property :record_id, Integer, :lazy=>false
27
+ property :mod_id, Integer, :lazy=>false
28
+ finalize_orig
29
+ end
30
+ end
31
+
32
+
33
+
34
+ module Adapters
35
+
36
+ class FilemakerAdapter < AbstractAdapter
37
+ @fmresultset_template_path = File.expand_path('../dm-fmresultset.yml', __FILE__).to_s
38
+ class << self; attr_accessor :fmresultset_template_path; end
39
+ VERSION = DataMapper::FilemakerAdapter::VERSION
40
+
41
+
42
+ ### UTILITY METHODS ###
43
+
44
+ # Class methods extended onto model.
45
+ module ModelMethods
46
+ def layout
47
+ Rfm.layout(storage_name, repository.adapter.options.symbolize_keys)
48
+ end
49
+ end
50
+
51
+ # Instance methods included in model.
52
+ module ResourceMethods
53
+ def layout
54
+ model.layout
55
+ end
56
+ end
57
+
58
+
59
+
60
+ ### ADAPTER CORE METHODS ###
61
+
62
+ # Persists one or many new resources
63
+ #
64
+ # @example
65
+ # adapter.create(collection) # => 1
66
+ #
67
+ # Adapters provide specific implementation of this method
68
+ #
69
+ # @param [Enumerable<Resource>] resources
70
+ # The list of resources (model instances) to create
71
+ #
72
+ # @return [Integer]
73
+ # The number of records that were actually saved into the data-store
74
+ #
75
+ # @api semipublic
76
+ def create(resources)
77
+ #resources[0].model.last_query = resources
78
+ counter = 0
79
+ resources.each do |resource|
80
+ fm_params = fmp_attributes resource.dirty_attributes
81
+ rslt = layout(resource.model).create(fm_params, :template=>self.class.fmresultset_template_path)
82
+ merge_fmp_response(resource, rslt[0])
83
+ counter +=1
84
+ end
85
+ counter
86
+ end
87
+
88
+ # Reads one or many resources from a datastore
89
+ #
90
+ # @example
91
+ # adapter.read(query) # => [ { 'name' => 'Dan Kubb' } ]
92
+ #
93
+ # Adapters provide specific implementation of this method
94
+ #
95
+ # @param [Query] query
96
+ # the query to match resources in the datastore
97
+ #
98
+ # @return [Enumerable<Hash>]
99
+ # an array of hashes to become resources
100
+ #
101
+ # @api semipublic
102
+ # def read(query)
103
+ # raise NotImplementedError, "#{self.class}#read not implemented"
104
+ # end
105
+ #
106
+ def read(query)
107
+ #query.model.last_query = query
108
+ #y query
109
+ _layout = layout(query.model)
110
+ opts = fmp_options(query)
111
+ opts[:template] = self.class.fmresultset_template_path
112
+ prms = fmp_query(query.conditions) #.to_set.first)
113
+ rslt = prms.empty? ? _layout.all(opts) : _layout.find(prms, opts)
114
+ rslt.dup.each_with_index(){|r, i| rslt[i] = r.to_h}
115
+ rslt
116
+ end
117
+
118
+ # Takes a query and returns number of matched records.
119
+ # An empty query will return the total record count
120
+ def aggregate(query)
121
+ #query.model.last_query = query
122
+ #y query
123
+ _layout = layout(query.model)
124
+ opts = fmp_options(query)
125
+ opts[:template] = self.class.fmresultset_template_path
126
+ prms = fmp_query(query.conditions) #.to_set.first)
127
+ #[prms.empty? ? _layout.all(:max_records=>0).foundset_count : _layout.count(prms)]
128
+ [prms.empty? ? _layout.view.total_count : _layout.count(prms)]
129
+ end
130
+
131
+ # Updates one or many existing resources
132
+ #
133
+ # @example
134
+ # adapter.update(attributes, collection) # => 1
135
+ #
136
+ # Adapters provide specific implementation of this method
137
+ #
138
+ # @param [Hash(Property => Object)] attributes
139
+ # hash of attribute values to set, keyed by Property
140
+ # @param [Collection] collection
141
+ # collection of records to be updated
142
+ #
143
+ # @return [Integer]
144
+ # the number of records updated
145
+ #
146
+ # @api semipublic
147
+ def update(attributes, collection)
148
+ #collection[0].model.last_query = [attributes, collection]
149
+ fm_params = fmp_attributes(attributes)
150
+ counter = 0
151
+ collection.each do |resource|
152
+ rslt = layout(resource.model).edit(resource.record_id, fm_params, :template=>self.class.fmresultset_template_path)
153
+ merge_fmp_response(resource, rslt[0])
154
+ resource.persistence_state = DataMapper::Resource::PersistenceState::Clean.new resource
155
+ counter +=1
156
+ end
157
+ counter
158
+ end
159
+
160
+ # Deletes one or many existing resources
161
+ #
162
+ # @example
163
+ # adapter.delete(collection) # => 1
164
+ #
165
+ # Adapters provide specific implementation of this method
166
+ #
167
+ # @param [Collection] collection
168
+ # collection of records to be deleted
169
+ #
170
+ # @return [Integer]
171
+ # the number of records deleted
172
+ #
173
+ # @api semipublic
174
+ def delete(collection)
175
+ counter = 0
176
+ collection.each do |resource|
177
+ rslt = layout(resource.model).delete(resource.record_id, :template=>self.class.fmresultset_template_path)
178
+ counter +=1
179
+ end
180
+ counter
181
+ end
182
+
183
+
184
+
185
+ ### ADAPTER HELPER METHODS ###
186
+
187
+ # Create fmp layout object from model object.
188
+ def layout(model)
189
+ #Rfm.layout(model.storage_name, options.symbolize_keys) #query.repository.adapter.options.symbolize_keys)
190
+ model.layout
191
+ end
192
+
193
+ # Convert dm query object to fmp query params (hash)
194
+ def fmp_query(input)
195
+ #puts "CONDITIONS input #{input.class.name} (#{input})"
196
+ if input.class.name[/OrOperation/]
197
+ input.operands.collect {|o| fmp_query o}
198
+ elsif input.class.name[/AndOperation/]
199
+ h = Hash.new
200
+ input.operands.each do |k,v|
201
+ r = fmp_query(k)
202
+ #puts "CONDITIONS operand #{r}"
203
+ if r.is_a?(Hash)
204
+ h.merge!(r)
205
+ else
206
+ h=r
207
+ break
208
+ end
209
+ end
210
+ h
211
+ elsif input.class.name[/NullOperation/] || input.nil?
212
+ {}
213
+ else
214
+ #puts "FMP_QUERY OPERATION #{input.class}"
215
+ val = input.loaded_value
216
+
217
+ if val.to_s != ''
218
+
219
+ operation = input.class.name
220
+ operator = case
221
+ when operation[/EqualTo/]; '='
222
+ when operation[/GreaterThan/]; '>'
223
+ when operation[/LessThan/]; '<'
224
+ when operation[/Like/]; ''
225
+ when operation[/Null/]; ''
226
+ else ''
227
+ end
228
+
229
+ val = val._to_fm if val.respond_to? :_to_fm
230
+ {input.subject.field.to_s => "#{operator}#{val}"}
231
+ else
232
+ {}
233
+ end
234
+ end
235
+ end
236
+
237
+
238
+ # Convert dm attributes hash to regular hash
239
+ # TODO: Should the result be string or symbol keys?
240
+ def fmp_attributes(attributes)
241
+ #puts "ATTRIBUTES"
242
+ y attributes
243
+ fm_params = Hash.new
244
+ attributes.to_h.each do |k,v|
245
+ fm_params[k.field] = v.respond_to?(:_to_fm) ? v._to_fm : v
246
+ end
247
+ # fm_params = Hash.new
248
+ # resource.dirty_attributes.each do |a,v|
249
+ # fm_params[a.field] = v.respond_to?(:_to_fm) ? v._to_fm : v
250
+ # end
251
+ fm_params
252
+ end
253
+
254
+ # Get fmp options hash from query
255
+ def fmp_options(query)
256
+ fm_options = {}
257
+ fm_options[:skip_records] = query.offset if query.offset
258
+ fm_options[:max_records] = query.limit if query.limit
259
+ if query.order
260
+ fm_options[:sort_field] = query.order.collect do |ord|
261
+ ord.target.field
262
+ end
263
+ fm_options[:sort_order] = query.order.collect do |ord|
264
+ ord.operator.to_s + 'end'
265
+ end
266
+ end
267
+ fm_options
268
+ end
269
+
270
+ def merge_fmp_response(resource, record)
271
+ resource.model.properties.to_a.each do |property|
272
+ if record.key?(property.field.to_s)
273
+ resource[property.name] = record[property.field.to_s]
274
+ end
275
+ end
276
+ end
277
+
278
+ # # This is supposed to convert property objects to field name. Not sure if it works.
279
+ # def get_field_name(field)
280
+ # return field.field if field.respond_to? :field
281
+ # field
282
+ # end
283
+
284
+
285
+ protected :fmp_query, :fmp_attributes, :fmp_options, :merge_fmp_response
286
+
287
+ end # FilemakerAdapter
288
+ end # Adapters
289
+ end # DataMapper
290
+
291
+ class Time
292
+ def _to_fm
293
+ d = strftime('%m/%d/%Y') unless Date.today == Date.parse(self.to_s)
294
+ t = strftime('%T')
295
+ d ? "#{d} #{t}" : t
296
+ end
297
+ end # Time
298
+
299
+ class DateTime
300
+ def _to_fm
301
+ d = strftime('%m/%d/%Y')
302
+ t =strftime('%T')
303
+ "#{d} #{t}"
304
+ end
305
+ end # Time
306
+
307
+ class Timestamp
308
+ def _to_fm
309
+ d = strftime('%m/%d/%Y')
310
+ t =strftime('%T')
311
+ "#{d} #{t}"
312
+ end
313
+ end # Time
314
+
315
+ class Date
316
+ def _to_fm
317
+ strftime('%m/%d/%Y')
318
+ end
319
+ end # Time
320
+
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+ # YAML structure defining a SAX parsing scheme for fmresultset xml.
3
+ # The initial object of this parse should be a new instance of Rfm::Resultset.
4
+ ---
5
+ attach_elements: _meta
6
+ attach_attributes: _meta
7
+ create_accessors: all
8
+ elements:
9
+ - name: doctype
10
+ attach: none
11
+ attributes:
12
+ - name: value
13
+ as_name: doctype
14
+ - name: fmresultset
15
+ attach: none
16
+ - name: product
17
+ - name: error
18
+ attach: none
19
+ before_close: :check_for_errors
20
+ attributes:
21
+ - name: code
22
+ as_name: error
23
+ - name: datasource
24
+ attach: none
25
+ before_close: [object, end_datasource_element_callback, self]
26
+ attributes:
27
+ - name: total_count
28
+ accessor: none
29
+ - name: metadata
30
+ attach: none
31
+ - name: field_definition
32
+ # These two steps can be used to create the attachment to resultset-meta automatically,
33
+ # but the field-mapping translation won't happen.
34
+ # attach: [_meta, 'Rfm::Metadata::Field', allocate]
35
+ # as_name: field_meta
36
+ attach: [cursor, 'Rfm::Metadata::Field', ':allocate']
37
+ delimiter: name
38
+ attach_attributes: private
39
+ before_close: [object, field_definition_element_close_callback, self]
40
+ - name: relatedset_definition
41
+ delimiter: table
42
+ as_name: portal_meta
43
+ attach_attributes: private
44
+ elements:
45
+ - name: field_definition
46
+ attach: [cursor, 'Rfm::Metadata::Field', ':allocate']
47
+ delimiter: name
48
+ as_name: field_meta
49
+ attach_attributes: private
50
+ before_close: [object, relatedset_field_definition_element_close_callback, self]
51
+ - name: resultset
52
+ attach: none
53
+ attributes:
54
+ - name: count
55
+ accessor: none
56
+ - name: fetch_size
57
+ accessor: none
58
+ - name: record
59
+ #attach: [cursor, object, handle_new_record, _attributes]
60
+ #attach_attributes: none
61
+ attach: [array, 'Rfm::Record', new, object]
62
+ attach_attributes: hash
63
+ before_close: '@loaded=true'
64
+ elements:
65
+ - name: field
66
+ attach: [cursor, 'Rfm::Metadata::Datum', ':allocate']
67
+ compact: false
68
+ before_close: [object, field_element_close_callback, self]
69
+ - name: relatedset
70
+ attach: [private, Array, ':allocate']
71
+ as_name: portals
72
+ attach_attributes: private
73
+ create_accessors: all
74
+ delimiter: table
75
+ elements:
76
+ - name: record
77
+ #class: Rfm::Record
78
+ attach: [default, 'Rfm::Record', ':allocate']
79
+ attach_attributes: hash
80
+ before_close: '@loaded=true'
81
+ elements:
82
+ - name: field
83
+ compact: true
84
+ attach: [cursor, 'Rfm::Metadata::Datum', ':allocate']
85
+ before_close: [object, portal_field_element_close_callback, self]
86
+
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module FilemakerAdapter
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require 'dm-core'
2
+ require 'dm-core/adapters/abstract_adapter'
3
+ require "dm-filemaker-adapter/version"
4
+ require 'dm-filemaker-adapter/adapter'
5
+ require 'rfm'
6
+
7
+
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe DataMapper::Adapters::FilemakerAdapter do
4
+ it 'has a version number' do
5
+ expect(DataMapper::Adapters::FilemakerAdapter::VERSION).not_to be nil
6
+ end
7
+
8
+ it 'does something useful' do
9
+ expect(true).to eq(true)
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'dm-filemaker-adapter'
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-filemaker-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - William Richardson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: data_mapper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ginjo-rfm
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Use Filemaker Server as a datastore for DataMapper ORM
84
+ email:
85
+ - https://github.com/ginjo/dm-filemaker-adapter
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .rspec
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - dm-filemaker-adapter.gemspec
97
+ - lib/dm-filemaker-adapter.rb
98
+ - lib/dm-filemaker-adapter/adapter.rb
99
+ - lib/dm-filemaker-adapter/dm-fmresultset.yml
100
+ - lib/dm-filemaker-adapter/version.rb
101
+ - spec/dm-filemaker-adapter/adapter_spec.rb
102
+ - spec/spec_helper.rb
103
+ homepage: ''
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.4.5
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Filemaker adapter for DataMapper
127
+ test_files:
128
+ - spec/dm-filemaker-adapter/adapter_spec.rb
129
+ - spec/spec_helper.rb