contentful_model 0.0.8 → 0.1.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/lib/contentful_model.rb +3 -5
- data/lib/contentful_model/associations/associations.rb +13 -0
- data/lib/contentful_model/associations/belongs_to.rb +17 -0
- data/lib/contentful_model/associations/belongs_to_many.rb +69 -0
- data/lib/contentful_model/associations/has_many.rb +44 -0
- data/lib/contentful_model/associations/has_one.rb +42 -0
- data/lib/contentful_model/base.rb +18 -4
- data/lib/contentful_model/errors.rb +4 -0
- data/lib/contentful_model/version.rb +1 -1
- metadata +22 -3
- data/lib/contentful_model/associations.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c1cf9bc5fe07bc623e3d1bc3d3ae0b8d85c9fb
|
4
|
+
data.tar.gz: 918055df94e083db1816f5fcc527e54e831a2227
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a754f0bb73a6909c161f66a24c498d6c4287f50bc0581fe90688973dada28402dab54cf60d2b92bc29e0a9c1fbdf7c6f77d48cb23e78dedd53738fec184205d
|
7
|
+
data.tar.gz: 2423688b78f546b97b64b318772ebe7de72d773bbe7cc0c7da065d3eec039616887525c5ddd7a160d9970ea48540a03aafe2f2a8069dbc8e21abe9d2246ba23a
|
data/lib/contentful_model.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
+
require 'require_all'
|
1
2
|
require 'contentful'
|
2
|
-
|
3
|
-
|
4
|
-
require "contentful_model/chainable_queries"
|
5
|
-
require "contentful_model/associations"
|
6
|
-
require "contentful_model/base"
|
3
|
+
require_rel '.'
|
4
|
+
|
7
5
|
require "active_support/all"
|
8
6
|
|
9
7
|
module ContentfulModel
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# A module to map relationships, a little like ActiveRecord::Relation
|
2
|
+
# This is necessary because Contentful::Link classes are not 2-way, so you can't
|
3
|
+
# get the parent from a child.
|
4
|
+
module ContentfulModel
|
5
|
+
module Associations
|
6
|
+
def self.included(base)
|
7
|
+
base.include HasMany
|
8
|
+
base.include HasOne
|
9
|
+
base.include BelongsTo
|
10
|
+
base.include BelongsToMany
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ContentfulModel
|
2
|
+
module Associations
|
3
|
+
module BelongsTo
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# belongs_to is called on the child, and creates methods for mapping to the parent
|
10
|
+
# @param association_name [Symbol] the singular name of the parent
|
11
|
+
def belongs_to(association_name, opts = {})
|
12
|
+
raise NotImplementedError, "Contentful doesn't have a singular belongs_to relationship. Use belongs_to_many instead."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module ContentfulModel
|
2
|
+
module Associations
|
3
|
+
module BelongsToMany
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
module ClassMethods
|
8
|
+
# belongs_to_many implements a has_many association from the opposite end, and allows a call to the association name
|
9
|
+
# to return all instances for which this object is a child.
|
10
|
+
#
|
11
|
+
# It's moderately expensive because we have to iterate over every parent, checking whether this instance
|
12
|
+
# is in the children. It requires one API call.
|
13
|
+
|
14
|
+
# class Bar
|
15
|
+
# belongs_to_many :foos, class_name: Foo, inverse_of: :special_bars
|
16
|
+
# end
|
17
|
+
|
18
|
+
# In this example, children on the parent are accessed through an association called special_bars.
|
19
|
+
|
20
|
+
# @param association_names [Symbol] plural name of the class we need to search through, to find this class
|
21
|
+
# @param options [true, Hash] options
|
22
|
+
def belongs_to_many(association_names, opts = {})
|
23
|
+
default_options = {
|
24
|
+
class_name: association_names.to_s.singularize.classify,
|
25
|
+
inverse_of: self.to_s.underscore.to_sym
|
26
|
+
}
|
27
|
+
options = default_options.merge(opts)
|
28
|
+
if self.respond_to?(association_names)
|
29
|
+
self.send(association_names)
|
30
|
+
else
|
31
|
+
define_method "#{association_names}" do
|
32
|
+
parents = instance_variable_get(:"@#{association_names}")
|
33
|
+
if parents.nil?
|
34
|
+
#get the parent class objects as an array
|
35
|
+
parent_objects = options[:class_name].constantize.send(:all).send(:load)
|
36
|
+
#iterate through parent objects and see if any of the children include the same ID as the method
|
37
|
+
parents = parent_objects.select do |parent_object|
|
38
|
+
#check to see if the parent object responds to the plural or singular.
|
39
|
+
if parent_object.respond_to?(:"#{options[:inverse_of].to_s.pluralize}")
|
40
|
+
collection_of_children_on_parent = parent_object.send(:"#{options[:inverse_of].to_s.pluralize}")
|
41
|
+
#get the collection of children from the parent. This *might* be nil if the parent doesn't have
|
42
|
+
# any children, in which case, just skip over this parent item and move on to the next.
|
43
|
+
if collection_of_children_on_parent.nil?
|
44
|
+
next
|
45
|
+
else
|
46
|
+
collection_of_children_on_parent.collect(&:id).include?(id)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
#if it doesn't respond to the plural, assume singular
|
50
|
+
child_on_parent = parent_object.send(:"#{options[:inverse_of]}")
|
51
|
+
# Do the same skipping routine on nil.
|
52
|
+
if child_on_parent.nil?
|
53
|
+
next
|
54
|
+
else
|
55
|
+
child_on_parent.send(:id) == id
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
instance_variable_set(:"@#{association_names}",parents)
|
61
|
+
end
|
62
|
+
parents
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ContentfulModel
|
2
|
+
module Associations
|
3
|
+
module HasMany
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# has_many is called on the parent model
|
10
|
+
#
|
11
|
+
# e.g
|
12
|
+
# class Foo
|
13
|
+
# has_many :bars, class_name: "Something"
|
14
|
+
# end
|
15
|
+
# The only reason for this method is that we might want to specify a relationship which is different
|
16
|
+
# from the name of the model we're calling. If you specify a class_name, the method called on the parent will
|
17
|
+
# be that. e.g. .somethings in this example
|
18
|
+
# @param association_names [Symbol] the name of the child model, as a plural symbol
|
19
|
+
def has_many(association_names, options = {})
|
20
|
+
default_options = {
|
21
|
+
class_name: association_names.to_s.singularize.classify
|
22
|
+
}
|
23
|
+
options = default_options.merge(options)
|
24
|
+
define_method association_names do
|
25
|
+
begin
|
26
|
+
# try calling the association name directly on the superclass - will be picked up by
|
27
|
+
# ContentfulModel::Base#method_missing and return a value if there is one for the attribute
|
28
|
+
super()
|
29
|
+
rescue ContentfulModel::AttributeNotFoundError
|
30
|
+
# If AttributeNotFoundError is raised, that means that the association name isn't available on the object.
|
31
|
+
# We try to call the class name (pluralize) instead, or give up and return an empty collection
|
32
|
+
if options[:class_name].pluralize.underscore.to_sym != association_names
|
33
|
+
self.send(options[:class_name].pluralize.underscore.to_sym)
|
34
|
+
else
|
35
|
+
#return an empty collection if the class name was the same as the association name and there's no attribute on the object.
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ContentfulModel
|
2
|
+
module Associations
|
3
|
+
module HasOne
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
#has_one defines a method on the parent which wraps around the superclass's implementation. In most cases this
|
10
|
+
#will end up at ContentfulModel::Base#method_missing and look at the fields on a content object.
|
11
|
+
#We wrap around it like this so we can specify a class_name option to call a different method from the association
|
12
|
+
#name.
|
13
|
+
# class Foo
|
14
|
+
# has_one :special_bar, class_name: "Bar"
|
15
|
+
# end
|
16
|
+
# @param association_name [Symbol] the name of the association. In this case Foo.special_bar.
|
17
|
+
# @param options [Hash] a hash, the only key of which is important is class_name.
|
18
|
+
def has_one(association_name, options = {})
|
19
|
+
default_options = {
|
20
|
+
class_name: association_name.to_s.classify
|
21
|
+
}
|
22
|
+
options = default_options.merge(options)
|
23
|
+
# Define a method which matches the association name
|
24
|
+
define_method association_name do
|
25
|
+
begin
|
26
|
+
# Start by calling the association name as a method on the superclass. This will probably end up at ContentfulModel::Base#method_missing
|
27
|
+
super()
|
28
|
+
rescue ContentfulModel::AttributeNotFoundError
|
29
|
+
# If method_missing returns an error, the field doesn't exist. If a class is specified, try that.
|
30
|
+
if options[:class_name].underscore.to_sym != association_name
|
31
|
+
self.send(options[:class_name].underscore.to_sym)
|
32
|
+
else
|
33
|
+
#otherwise give up and return nil
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -12,12 +12,22 @@ module ContentfulModel
|
|
12
12
|
def method_missing(method, *args, &block)
|
13
13
|
result = fields[:"#{method.to_s.camelize(:lower)}"]
|
14
14
|
if result.nil?
|
15
|
-
|
15
|
+
raise ContentfulModel::AttributeNotFoundError, "no attribute #{method} found"
|
16
16
|
else
|
17
|
+
# if there's no coercion specified, return the result
|
17
18
|
if self.class.coercions[method].nil?
|
18
19
|
return result
|
19
|
-
|
20
|
+
|
21
|
+
#if there's a coercion specified for the field and it's a proc, pass the result
|
22
|
+
#to the proc
|
23
|
+
elsif self.class.coercions[method].is_a?(Proc)
|
24
|
+
return self.class.coercions[method].call(result)
|
25
|
+
#provided the coercion is in the COERCIONS constant, call the proc on that
|
26
|
+
elsif !self.class::COERCIONS[self.class.coercions[method]].nil?
|
20
27
|
return self.class::COERCIONS[self.class.coercions[method]].call(result)
|
28
|
+
else
|
29
|
+
#... or just return the result
|
30
|
+
return result
|
21
31
|
end
|
22
32
|
end
|
23
33
|
end
|
@@ -67,8 +77,12 @@ module ContentfulModel
|
|
67
77
|
client.content_type(@content_type_id)
|
68
78
|
end
|
69
79
|
|
70
|
-
def coerce_field(
|
71
|
-
|
80
|
+
def coerce_field(*coercions)
|
81
|
+
@coercions ||= {}
|
82
|
+
coercions.each do |coercions_hash|
|
83
|
+
@coercions.merge!(coercions_hash)
|
84
|
+
end
|
85
|
+
@coercions
|
72
86
|
end
|
73
87
|
|
74
88
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contentful_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Error Creative Studio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: contentful
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: require_all
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: A wrapper around the Contentful gem to give you a base class to inherit
|
56
70
|
your models from
|
57
71
|
email:
|
@@ -63,9 +77,14 @@ files:
|
|
63
77
|
- MIT-LICENSE
|
64
78
|
- Rakefile
|
65
79
|
- lib/contentful_model.rb
|
66
|
-
- lib/contentful_model/associations.rb
|
80
|
+
- lib/contentful_model/associations/associations.rb
|
81
|
+
- lib/contentful_model/associations/belongs_to.rb
|
82
|
+
- lib/contentful_model/associations/belongs_to_many.rb
|
83
|
+
- lib/contentful_model/associations/has_many.rb
|
84
|
+
- lib/contentful_model/associations/has_one.rb
|
67
85
|
- lib/contentful_model/base.rb
|
68
86
|
- lib/contentful_model/chainable_queries.rb
|
87
|
+
- lib/contentful_model/errors.rb
|
69
88
|
- lib/contentful_model/queries.rb
|
70
89
|
- lib/contentful_model/query.rb
|
71
90
|
- lib/contentful_model/version.rb
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# A module to map relationships, a little like ActiveRecord::Relation
|
2
|
-
# This is necessary because Contentful::Link classes are not 2-way, so you can't
|
3
|
-
# get the parent from a child.
|
4
|
-
module ContentfulModel
|
5
|
-
module Associations
|
6
|
-
def self.included(base)
|
7
|
-
base.extend ClassMethods
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
# has_many is called on the parent model, and sets an instance var on the child
|
12
|
-
# which is named the plural of the class this module is mixed into.
|
13
|
-
#
|
14
|
-
# e.g
|
15
|
-
# class Foo
|
16
|
-
# has_many :bars
|
17
|
-
# end
|
18
|
-
# @param classname [Symbol] the name of the child model, as a plural symbol
|
19
|
-
def has_many(classname)
|
20
|
-
#define an instance method called the same as the arg passed in
|
21
|
-
#e.g. bars()
|
22
|
-
define_method "#{classname}" do
|
23
|
-
# call bars() on super, and for each, call bar=(self)
|
24
|
-
super().collect do |instance|
|
25
|
-
instance.send(:"#{self.class.to_s.singularize.camelize(:lower)}=",self)
|
26
|
-
#return the instance to the collect() method
|
27
|
-
instance
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# has_one is called on the parent model, and sets a single instance var on the child
|
33
|
-
# it's conceptually identical to `has_many()`
|
34
|
-
# which is named the singular of the class this module is mixed into
|
35
|
-
def has_one(classname)
|
36
|
-
define_method "#{classname}" do
|
37
|
-
super().send(:"#{self.class.to_s.singularize.camelize(:lower)}=",self)
|
38
|
-
instance
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
# belongs_to is called on the child, and creates methods for mapping to the parent
|
44
|
-
# @param classname [Symbol] the singular name of the parent
|
45
|
-
def belongs_to(classname)
|
46
|
-
raise ArgumentError, "belongs_to requires a class name as a symbol" unless classname.is_a?(Symbol)
|
47
|
-
define_method "#{classname}" do
|
48
|
-
#this is where we need to return the parent class
|
49
|
-
self.instance_variable_get(:"@#{classname}")
|
50
|
-
end
|
51
|
-
|
52
|
-
define_method "#{classname}=" do |instance|
|
53
|
-
#this is where we need to set the class name
|
54
|
-
self.instance_variable_set(:"@#{classname}",instance)
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|