cdq 0.1.1
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 +15 -0
- data/.gitignore +11 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +32 -0
- data/README.md +173 -0
- data/Rakefile +24 -0
- data/app/app_delegate.rb +13 -0
- data/app/test_models.rb +15 -0
- data/cdq.gemspec +18 -0
- data/lib/cdq.rb +12 -0
- data/lib/cdq/version.rb +4 -0
- data/motion/cdq.rb +58 -0
- data/motion/cdq/collection_proxy.rb +29 -0
- data/motion/cdq/config.rb +67 -0
- data/motion/cdq/context.rb +190 -0
- data/motion/cdq/model.rb +32 -0
- data/motion/cdq/object.rb +83 -0
- data/motion/cdq/object_proxy.rb +30 -0
- data/motion/cdq/partial_predicate.rb +53 -0
- data/motion/cdq/query.rb +128 -0
- data/motion/cdq/relationship_query.rb +122 -0
- data/motion/cdq/store.rb +52 -0
- data/motion/cdq/targeted_query.rb +170 -0
- data/motion/managed_object.rb +98 -0
- data/resources/CDQ.xcdatamodeld/.xccurrentversion +8 -0
- data/resources/CDQ.xcdatamodeld/0.0.1.xcdatamodel/contents +34 -0
- data/resources/Default-568h@2x.png +0 -0
- data/resources/KEEPME +0 -0
- data/schemas/001_baseline.rb +44 -0
- data/spec/cdq/collection_proxy_spec.rb +51 -0
- data/spec/cdq/config_spec.rb +74 -0
- data/spec/cdq/context_spec.rb +92 -0
- data/spec/cdq/managed_object_spec.rb +81 -0
- data/spec/cdq/model_spec.rb +14 -0
- data/spec/cdq/module_spec.rb +44 -0
- data/spec/cdq/object_proxy_spec.rb +37 -0
- data/spec/cdq/object_spec.rb +58 -0
- data/spec/cdq/partial_predicate_spec.rb +52 -0
- data/spec/cdq/query_spec.rb +127 -0
- data/spec/cdq/relationship_query_spec.rb +75 -0
- data/spec/cdq/store_spec.rb +39 -0
- data/spec/cdq/targeted_query_spec.rb +120 -0
- data/spec/helpers/thread_helper.rb +16 -0
- data/spec/integration_spec.rb +38 -0
- data/vendor/cdq/ext/CoreDataQueryManagedObjectBase.h +8 -0
- data/vendor/cdq/ext/CoreDataQueryManagedObjectBase.m +22 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjBhMWJiZjc1MTc0OGQyMzM4NTEwN2ZkMGIyOWQ3MTJmODdiNWZhYg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NmE3MTQ2MjIyMmYxYTJiYzg4OTJmMDYxMjk5ZjE4YWU2YjgzMzY1Nw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YTBlZTY0NDE4NzIxMDY2ODcxMmUzNGMxM2M3OWFhYTExM2RjYjc1ZWI2NjRh
|
10
|
+
MTFiZjUyNzIwY2VlMDRmOTk3MTFmMGE2MTg0YTQ3YTljMTJlZGVkNWJkYjJm
|
11
|
+
NzZlZjYzYWRiODQ2OGVhNzNjNGUwOTliMDhkNzZiZDQ3YmU1YTE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YmM1Njk2Nzg3ODBkODYxMjAxOWNlNmVkZWU3ZTg0YzNhMDBjOTQ5OTljNjcx
|
14
|
+
OWJiODM1MGYxOGNlODg1NGM4MzY3MzEzZjUyM2I5OTE5OGEwZGE0YmNlMjkx
|
15
|
+
NzkxNjlkNzIzYzQyZGYxODQxZmIyNjg2NGQwOTk1ZWJiODczYzI=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cdq (0.1.1)
|
5
|
+
motion-yaml
|
6
|
+
ruby-xcdm (~> 0.0, >= 0.0.5)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activesupport (3.2.16)
|
12
|
+
i18n (~> 0.6, >= 0.6.4)
|
13
|
+
multi_json (~> 1.0)
|
14
|
+
builder (3.2.2)
|
15
|
+
i18n (0.6.9)
|
16
|
+
motion-stump (0.3.0)
|
17
|
+
motion-yaml (1.2)
|
18
|
+
multi_json (1.8.2)
|
19
|
+
plist (3.1.0)
|
20
|
+
rake (10.1.0)
|
21
|
+
ruby-xcdm (0.0.5)
|
22
|
+
activesupport (~> 3.2)
|
23
|
+
builder (~> 3.2)
|
24
|
+
plist (~> 3.1)
|
25
|
+
|
26
|
+
PLATFORMS
|
27
|
+
ruby
|
28
|
+
|
29
|
+
DEPENDENCIES
|
30
|
+
cdq!
|
31
|
+
motion-stump
|
32
|
+
rake
|
data/README.md
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
|
2
|
+
# Streamlined Core Data for RubyMotion
|
3
|
+
|
4
|
+
Core Data Query (CDQ) is a library to help you manage your Core Data stack
|
5
|
+
while using RubyMotion. It uses a data model file, which you can generate in
|
6
|
+
XCode, or you can use [ruby-xcdm](https://github.com/infinitered/ruby-xcdm).
|
7
|
+
CDQ aims to streamline the process of getting you up and running Core Data, while
|
8
|
+
avoiding too much abstraction or method pollution on top of the SDK.
|
9
|
+
|
10
|
+
CDQ began its life as a fork of
|
11
|
+
[MotionData](https://github.com/alloy/MotionData), but it became obvious I
|
12
|
+
wanted to take things in a different direction, so I cut loose and ended up
|
13
|
+
rewriting almost everything. If you pay attention, you can still find the
|
14
|
+
genetic traces, so thanks to @alloy for sharing his work and letting me learn
|
15
|
+
so much.
|
16
|
+
|
17
|
+
### Why use a static Data Model?
|
18
|
+
|
19
|
+
By using a real data model file that gets compiled and included in your bundle,
|
20
|
+
you can take advantage of automatic migration, which simplifies managing your
|
21
|
+
schema as it grows, if you can follow a few simple rules.
|
22
|
+
|
23
|
+
## Installing
|
24
|
+
|
25
|
+
Using Bundler:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'cdq'
|
29
|
+
```
|
30
|
+
|
31
|
+
If you want to see bleeding-edge changes, point Bundler at the git repo:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
gem 'cdq', git: 'git://github.com/infinitered/cdq.git'
|
35
|
+
```
|
36
|
+
|
37
|
+
## Setting up your stack
|
38
|
+
|
39
|
+
You will need a data model file. If you've created one in XCode, move or copy
|
40
|
+
it to your resources file and make sure it's named the same as your RubyMotion
|
41
|
+
project. If you're using `ruby-xcdm` (which I highly recommend) then it will
|
42
|
+
create the datamodel file automatically and put it in the right place.
|
43
|
+
|
44
|
+
Now include the setup code in your `app_delegate.rb` file:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class AppDelegate
|
48
|
+
include CDQ
|
49
|
+
|
50
|
+
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
51
|
+
cdq.setup
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class TopLevel
|
57
|
+
include CDQ
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
That's it! You can create specific implementation classes for your entities if
|
62
|
+
you want, but it's not required. You can start running queries on the console or
|
63
|
+
in your code right away.
|
64
|
+
|
65
|
+
## Creating new objects
|
66
|
+
|
67
|
+
CDQ maintains a stack of NSManagedObjectContexts for you, and any create
|
68
|
+
operations will insert new, unsaved objects into the context currently on top
|
69
|
+
of the stack. `cdq.save` will save the whole stack, including correctly using
|
70
|
+
private threads if appropriate.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
cdq('Author').create(name: "Le Guin", publish_count: 150, first_published: 1970)
|
74
|
+
cdq('Author').create(name: "Shakespeare", publish_count: 400, first_published: 1550)
|
75
|
+
cdq('Author').create(name: "Blake", publish_count: 100, first_published: 1778)
|
76
|
+
cdq.save
|
77
|
+
|
78
|
+
```
|
79
|
+
|
80
|
+
## Queries
|
81
|
+
|
82
|
+
A quick aside about queries in Core Data. You should avoid them whenever
|
83
|
+
possible in your production code. Core Data is designed to work efficiently
|
84
|
+
when you hang on to references to specific objects and use them as you would
|
85
|
+
any in-memory object, letting Core Data handle your memory usage for you. If
|
86
|
+
you're coming from a server-side rails background, this can be pretty hard to
|
87
|
+
get used to, but this is a very different environment. So if you find yourself
|
88
|
+
running queries that only return a single object, consider rearchitecting.
|
89
|
+
That said, queries are sometimes the only solution, and it's very handy to be
|
90
|
+
able to use them easily when debugging from the console, or in unit tests.
|
91
|
+
|
92
|
+
With that out of the way, here are some samples:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
# Simple Queries
|
96
|
+
cdq('Author').where(:name).eq('Shakespeare')
|
97
|
+
cdq('Author').where(:publish_count).gt(10)
|
98
|
+
|
99
|
+
# sort, limit, and offset
|
100
|
+
cdq('Author').sort_by(:created_at).limit(1).offset(10)
|
101
|
+
|
102
|
+
# Compound queries
|
103
|
+
cdq('Author').where(:name).eq('Blake').and(:first_published).le(Time.local(1700))
|
104
|
+
|
105
|
+
# Multiple comparisons against the same attribute
|
106
|
+
cdq('Author').where(:created_at).ge(yesterday).and.lt(today)
|
107
|
+
```
|
108
|
+
|
109
|
+
## Named Scopes
|
110
|
+
|
111
|
+
You can save up partially-constructed queries for later use using named scopes, even
|
112
|
+
combining them seamlessly with other queries or other named scopes:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
cdq('Author').scope :a_authors, cdq(:name).begins_with('A')
|
116
|
+
cdq('Author').scope :prolific, cdq(:publish_count).gt(99)
|
117
|
+
|
118
|
+
cdq('Author').prolific.a_authors.limit(5)
|
119
|
+
```
|
120
|
+
|
121
|
+
> NOTE: strings and symbols are NOT interchangeable. `cdq('Entity')` gives you a
|
122
|
+
query generator for an entity, but `cdq(:attribute)` starts a predicate for an
|
123
|
+
attribute.
|
124
|
+
|
125
|
+
## Dedicated Models
|
126
|
+
|
127
|
+
If you're using CDQ in a brand new project, you'll probably want to use
|
128
|
+
dedicated model classes for your entities. It will enable the usual
|
129
|
+
class-level customization of your model objects, and also a somewhat more
|
130
|
+
familiar-looking and natural syntax for queries and scopes:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
class Author < CDQManagedOjbect
|
134
|
+
scope :a_authors, cdq(:name).begins_with('A')
|
135
|
+
scope :prolific, cdq(:publish_count).gt(99)
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
Now you can change the queries above to:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
Author.where(:name).eq('Shakespeare')
|
143
|
+
Author.where(:publish_count).gt(10)
|
144
|
+
Author.where(:name).eq('Blake').and(:first_published).le(Time.local(1700))
|
145
|
+
Author.where(:created_at).ge(yesterday).and.lt(today)
|
146
|
+
Author.prolific.a_authors.limit(5)
|
147
|
+
```
|
148
|
+
|
149
|
+
Anything you can do with `cdq('Author')` you can now do with just `Author`. If you have a
|
150
|
+
pre-existing implementation class that you can't turn into a CDQManagedObject, you can also
|
151
|
+
just wrap the class: `cdq(Author)`.
|
152
|
+
|
153
|
+
## Using CDQ with a pre-existing model
|
154
|
+
|
155
|
+
If you have an existing app that already manages its own data model, you can
|
156
|
+
use that, too, and override CDQ's stack at any layer:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
cdq.setup(context: App.delegate.mainContext) # don't set up model or store coordinator
|
160
|
+
cdq.setup(store: App.delegate.persistentStoreCoordinator) # Don't set up model
|
161
|
+
cdq.setup(model: App.delegate.managedObjectModel) # Don't load model
|
162
|
+
```
|
163
|
+
|
164
|
+
You cannot use CDQManagedObject as a base class when overriding this way,
|
165
|
+
you'll need to use <tt>cdq('Entity')</tt>. If you have an existing model and
|
166
|
+
want to use it with CDQManagedObject without changing its name, You'll need to
|
167
|
+
use a <tt>cdq.yml</tt> config file. See [CDQConfig](motion/cdq/config.rb).
|
168
|
+
|
169
|
+
## Things that are currently missing
|
170
|
+
|
171
|
+
* There is no facility for custom migrations yet
|
172
|
+
* There are no explicit validations (but you can define them on your data model)
|
173
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift("/Library/RubyMotion/lib")
|
2
|
+
require 'motion/project/template/ios'
|
3
|
+
|
4
|
+
require 'bundler'
|
5
|
+
require 'bundler/gem_tasks'
|
6
|
+
|
7
|
+
Motion::Project::App.setup do |app|
|
8
|
+
# Use `rake config' to see complete project settings.
|
9
|
+
app.name = 'CDQ'
|
10
|
+
app.vendor_project('vendor/cdq/ext', :static)
|
11
|
+
end
|
12
|
+
|
13
|
+
if ARGV.join(' ') =~ /spec/
|
14
|
+
Bundler.require :default, :spec
|
15
|
+
else
|
16
|
+
Bundler.require
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'cdq'
|
20
|
+
require 'motion-stump'
|
21
|
+
require 'ruby-xcdm'
|
22
|
+
require 'motion-yaml'
|
23
|
+
|
24
|
+
task :"build:simulator" => :"schema:build"
|
data/app/app_delegate.rb
ADDED
data/app/test_models.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class Author < CDQManagedObject
|
2
|
+
end
|
3
|
+
|
4
|
+
class Article < CDQManagedObject
|
5
|
+
scope :all_published, where(:published).eq(true)
|
6
|
+
scope :with_title, where(:title).ne(nil).sort_by(:title, :descending)
|
7
|
+
scope :published_since { |date| where(:publishedAt).ge(date) }
|
8
|
+
end
|
9
|
+
|
10
|
+
class Citation < CDQManagedObject
|
11
|
+
end
|
12
|
+
|
13
|
+
class Writer < CDQManagedObject
|
14
|
+
end
|
15
|
+
|
data/cdq.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/cdq/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["infinitered", "kemiller"]
|
6
|
+
gem.email = ["ken@infinitered.com"]
|
7
|
+
gem.description = "Core Data Query for RubyMotion"
|
8
|
+
gem.summary = "Core Data Query for RubyMotion"
|
9
|
+
gem.homepage = "http://github.com/infinitered/cdq"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
|
+
gem.name = "cdq"
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
gem.add_runtime_dependency 'ruby-xcdm', '~> 0.0', '>= 0.0.5'
|
16
|
+
gem.add_runtime_dependency 'motion-yaml'
|
17
|
+
gem.version = CDQ::VERSION
|
18
|
+
end
|
data/lib/cdq.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
unless defined?(Motion::Project::App)
|
3
|
+
raise "This must be required from within a RubyMotion Rakefile"
|
4
|
+
end
|
5
|
+
|
6
|
+
Motion::Project::App.setup do |app|
|
7
|
+
parent = File.join(File.dirname(__FILE__), '..')
|
8
|
+
app.files.unshift(Dir.glob(File.join(parent, "motion/cdq/**/*.rb")))
|
9
|
+
app.files.unshift(Dir.glob(File.join(parent, "motion/*.rb")))
|
10
|
+
app.frameworks += %w{ CoreData }
|
11
|
+
app.vendor_project(File.join(parent, 'vendor/cdq/ext'), :static)
|
12
|
+
end
|
data/lib/cdq/version.rb
ADDED
data/motion/cdq.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
module CDQ
|
3
|
+
|
4
|
+
class CDQObject; end
|
5
|
+
class CDQQuery < CDQObject; end
|
6
|
+
class CDQPartialPredicate < CDQObject; end
|
7
|
+
class CDQTargetedQuery < CDQQuery; end
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
def cdq(obj = nil)
|
12
|
+
obj ||= self
|
13
|
+
|
14
|
+
@@base_object ||= CDQObject.new
|
15
|
+
|
16
|
+
case obj
|
17
|
+
when Class
|
18
|
+
if obj.isSubclassOfClass(NSManagedObject)
|
19
|
+
entity_description = @@base_object.models.current.entitiesByName[obj.name]
|
20
|
+
if entity_description.nil?
|
21
|
+
raise "Cannot find an entity named #{obj.name}"
|
22
|
+
end
|
23
|
+
CDQTargetedQuery.new(entity_description, obj)
|
24
|
+
else
|
25
|
+
@@base_object
|
26
|
+
end
|
27
|
+
when String
|
28
|
+
entity_description = @@base_object.models.current.entitiesByName[obj]
|
29
|
+
target_class = NSClassFromString(entity_description.managedObjectClassName)
|
30
|
+
if entity_description.nil?
|
31
|
+
raise "Cannot find an entity named #{obj}"
|
32
|
+
end
|
33
|
+
CDQTargetedQuery.new(entity_description, target_class)
|
34
|
+
when Symbol
|
35
|
+
CDQPartialPredicate.new(obj, CDQQuery.new)
|
36
|
+
when CDQObject
|
37
|
+
obj
|
38
|
+
when NSManagedObject
|
39
|
+
CDQObjectProxy.new(obj)
|
40
|
+
when Array
|
41
|
+
if obj.first.class.isSubclassOfClass(NSManagedObject)
|
42
|
+
CDQCollectionProxy.new(obj, obj.first.entity)
|
43
|
+
else
|
44
|
+
@@base_object
|
45
|
+
end
|
46
|
+
else
|
47
|
+
@@base_object
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.pollute(klass)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class UIResponder
|
57
|
+
include CDQ
|
58
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module CDQ
|
3
|
+
class CDQCollectionProxy < CDQTargetedQuery
|
4
|
+
|
5
|
+
def initialize(objects, entity_description)
|
6
|
+
@objects = objects
|
7
|
+
super(entity_description, constantize(entity_description.managedObjectClassName))
|
8
|
+
@predicate = self.where("%@ CONTAINS SELF", @objects).predicate
|
9
|
+
end
|
10
|
+
|
11
|
+
def count
|
12
|
+
@objects.size
|
13
|
+
end
|
14
|
+
|
15
|
+
def get
|
16
|
+
@objects
|
17
|
+
end
|
18
|
+
|
19
|
+
def array
|
20
|
+
@objects
|
21
|
+
end
|
22
|
+
|
23
|
+
def first
|
24
|
+
@objects.first
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module CDQ
|
2
|
+
|
3
|
+
|
4
|
+
# = Configure the CDQ Stack
|
5
|
+
#
|
6
|
+
# This class wraps the YAML configuration file that will allow you to
|
7
|
+
# override the names used when setting up the database file and finding the
|
8
|
+
# model file. This file is named <tt>cdq.yml</tt> and must be found at the
|
9
|
+
# root of your resources directory. It supports the following top-level keys:
|
10
|
+
#
|
11
|
+
# [name] The root name for both database and model
|
12
|
+
# [database_name] The root name for the database file (relative to the documents directory)
|
13
|
+
# [model_name] The root name for the model file (relative to the bundle directory)
|
14
|
+
#
|
15
|
+
# Using the config file is not necessary. If you do not include it, the bundle display name
|
16
|
+
# will be used. For most people with a new app, this is what you want to do, especially if
|
17
|
+
# you are using ruby-xcdm schemas. The only case where using the config file is required
|
18
|
+
# is when you want to use CDQManagedObject-based models with a custom model or database, because
|
19
|
+
# class loading order of operations makes it impossible to configure from within your
|
20
|
+
# AppDelegate.
|
21
|
+
#
|
22
|
+
class CDQConfig
|
23
|
+
|
24
|
+
attr_reader :config_file, :database_name, :model_name, :name
|
25
|
+
|
26
|
+
def initialize(config_file)
|
27
|
+
case config_file
|
28
|
+
when String
|
29
|
+
@config_file = config_file
|
30
|
+
if File.file?(config_file)
|
31
|
+
h = File.open(config_file) { |f| YAML.load(f.read) }
|
32
|
+
else
|
33
|
+
h = {}
|
34
|
+
end
|
35
|
+
when Hash
|
36
|
+
h = config_file
|
37
|
+
else
|
38
|
+
h = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
@name = h['name'] || h[:name] || NSBundle.mainBundle.objectForInfoDictionaryKey("CFBundleDisplayName")
|
42
|
+
@database_name = h['database_name'] || h[:database_name] || name
|
43
|
+
@model_name = h['model_name'] || h[:model_name] || name
|
44
|
+
end
|
45
|
+
|
46
|
+
def database_url
|
47
|
+
dir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).last
|
48
|
+
path = File.join(dir, database_name + '.sqlite')
|
49
|
+
NSURL.fileURLWithPath(path)
|
50
|
+
end
|
51
|
+
|
52
|
+
def model_url
|
53
|
+
NSBundle.mainBundle.URLForResource(model_name, withExtension: "momd");
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.default
|
57
|
+
@default ||=
|
58
|
+
begin
|
59
|
+
cf_file = NSBundle.mainBundle.pathForResource("cdq", ofType: "yml");
|
60
|
+
new(cf_file)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|