pragmatic_context 0.0.2 → 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/Guardfile +4 -0
- data/README.md +77 -19
- data/lib/pragmatic_context/contextualizable.rb +23 -4
- data/lib/pragmatic_context/version.rb +1 -1
- data/pragmatic_context.gemspec +1 -0
- data/spec/lib/pragmatic_context/contextualizable_spec.rb +42 -5
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40b3f7414a092b590f39f53530c841de2eb6856b
|
4
|
+
data.tar.gz: c2690d5363e6ebe4f97d8ff1bf6f74eda15c9d0c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c73f9b9644b5cba0eec15b9057fa38d89a951cfbed66e1e20e6e87fbc3ab30140e1e7cf18930f780b2dd9dd320aaec424a941a23e99d3de6e6a3808b583e171
|
7
|
+
data.tar.gz: fdd45f04bd8b81024c96dc441a2b8539d59c77ec32e4a9cbb296a7f3a80a8c21eb6944d7e05d577608f3de4ac88005634c98fbc1cd088ab989ed3d5b3a03681b
|
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ get your models talking JSON-LD.
|
|
9
9
|
I'm glad you asked. [JSON-LD](http://json-ld.org/) is a lightweight JSON format
|
10
10
|
for expressing data within a context (also known as 'Linked Data'). Essentially
|
11
11
|
what this means is that it lets you say that the thing your data model calls
|
12
|
-
a 'last_name'
|
12
|
+
a 'last_name' (and what someone else may call 'family_name', or 'surname', or 'apellido') are all embodiments of the same abstract idea of a [Family
|
13
13
|
Name](http://xmlns.com/foaf/spec/#term_familyName). JSON-LD is similar in spirit
|
14
14
|
(though [vastly different in
|
15
15
|
execution](http://manu.sporny.org/2014/json-ld-origins-2/)) to
|
@@ -116,11 +116,15 @@ it like so:
|
|
116
116
|
contextualize :email, :as => 'http://xmlns.com/foaf/0.1/mbox'
|
117
117
|
end
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
the following JSON(-LD!) serialization:
|
119
|
+
This gives Pragmatic Context everything it needs to be able to create JSON-LD
|
120
|
+
representations of your model objects. Getting at these representations is
|
121
|
+
discussed in the following section.
|
123
122
|
|
123
|
+
### Getting at a JSON-LD representation
|
124
|
+
|
125
|
+
The `Contextualizable` mixin adds a `as_jsonld` method that returns a Hash
|
126
|
+
representation of your object, ready for serialization. Calling this method on
|
127
|
+
the `Person` object described above will produce the following JSON-LD document:
|
124
128
|
|
125
129
|
{
|
126
130
|
"@context": {
|
@@ -133,6 +137,74 @@ the following JSON(-LD!) serialization:
|
|
133
137
|
"email": "mat@geeky.net"
|
134
138
|
}
|
135
139
|
|
140
|
+
A couple of things to note about this implementation:
|
141
|
+
|
142
|
+
* `as_jsonld` will only serialize fields that have matching `contextualize`
|
143
|
+
statements. This is in keeping with JSON-LD's convention of ignoring fields in
|
144
|
+
a document which do not have a context defined.
|
145
|
+
* The produced JSON-LD document embeds the context directly in the document,
|
146
|
+
within the `@context` field.
|
147
|
+
* For each field present in your object's `as_json` method *that has a matching
|
148
|
+
`contextualize` statement*, `as_jsonld` will:
|
149
|
+
* If the field is a primitive value (string, number, boolean, nil), its
|
150
|
+
value will be copied directly from the output of `as_json`
|
151
|
+
* If the field is a nested object which includes `Contextualizable`, it is
|
152
|
+
recursively converted to JSON-LD by calling its `as_jsonld` method
|
153
|
+
* If the field is a Hash, its keys are copied over to the parent document's
|
154
|
+
representation, namespaced as per the field's `contextualize` statement.
|
155
|
+
More info on this case is given below.
|
156
|
+
|
157
|
+
#### Hash subdocuments and namespacing
|
158
|
+
|
159
|
+
As dicsussed above, subdocuments which are also `Contextualizable` are
|
160
|
+
automatically recused into and serialized into the output of `as_jsonld`. This
|
161
|
+
behaviour should be pretty straightforward to understand and make use of, but
|
162
|
+
doesn't clearly cover the case where you may want to refer to concepts in
|
163
|
+
separate vocabularies with similar names. In this case, Pragmatic Context
|
164
|
+
allows for namespacing based on nested hashes.
|
165
|
+
|
166
|
+
*This is an advanced use case and probably only useful if you know that you need
|
167
|
+
it. If this doesn't make sense to you, feel free to ignore it.*
|
168
|
+
|
169
|
+
Nested hashes which have a corresponding `contextualize` statement are copied into the
|
170
|
+
parent document within a namespace. This may seem confusing at first, but is
|
171
|
+
done principally to realize use cases such as the following:
|
172
|
+
|
173
|
+
class CreativeWork
|
174
|
+
include Mongoid::Document
|
175
|
+
include PragmaticContext::Contextualizable
|
176
|
+
|
177
|
+
field :dc, type: Hash
|
178
|
+
field :mods, type: Hash
|
179
|
+
|
180
|
+
contextualize :dc, :as => 'http://purl.org/dc/terms/'
|
181
|
+
contextualize :mods, :as => 'http://www.loc.gov/mods/rdf/v1#'
|
182
|
+
end
|
183
|
+
|
184
|
+
This allows for both dc['title'] and mods['title'] to be set to independent
|
185
|
+
values, and for the resulting document to serialize out as something like:
|
186
|
+
|
187
|
+
{
|
188
|
+
"@context": {
|
189
|
+
"dc": "http://purl.org/dc/terms/",
|
190
|
+
"mods": "http://www.loc.gov/mods/rdf/v1#',
|
191
|
+
},
|
192
|
+
"dc:title": "The value of dc['title']",
|
193
|
+
"mods:title": "The value of mods['title']"
|
194
|
+
}
|
195
|
+
|
196
|
+
### Custom serializers
|
197
|
+
|
198
|
+
If you want to refer to your JSON-LD context by URI (see Example 4 in the [JSON
|
199
|
+
spec](http://www.w3.org/TR/json-ld) for more info), or if you want to use your
|
200
|
+
own serializer to customize the JSON-LD representaions you produce, you'll want
|
201
|
+
to make use of the `Contextualizable` mixin's `context` method. `context`
|
202
|
+
returns a Hash object ready to be serialized into the `@context` field of the
|
203
|
+
output object. By wiring this up in whatever serializer your application uses,
|
204
|
+
you can easily extend custom serializations to output
|
205
|
+
valid JSON-LD.
|
206
|
+
|
207
|
+
|
136
208
|
### Dynamic documents & more complicated cases
|
137
209
|
|
138
210
|
There are cases (especially using Monogid's dynamic fields feature) where the
|
@@ -159,20 +231,6 @@ configured like so:
|
|
159
231
|
|
160
232
|
Examples of this are forthcoming.
|
161
233
|
|
162
|
-
## Known Issues
|
163
|
-
|
164
|
-
* `@type` values aren't yet handled in any real way. This is next up on my queue
|
165
|
-
and should be done very soon.
|
166
|
-
* The above example is purposely short on serialization specifics. I'm trying to
|
167
|
-
be accommodating of various serializers and I'm still figuring out the best
|
168
|
-
way to do this. Hopefully we'll be able to make the process of adding
|
169
|
-
a `@context` automatic (or close to it) for common cases. Suggestions for this
|
170
|
-
point are very welcome.
|
171
|
-
* Further to the above, there are many (most, even) use cases where the included
|
172
|
-
`@context` field should simply be a URI pointing to a stand-alone
|
173
|
-
represntation of the object's context. I'm not sure how to flexibly realize
|
174
|
-
this yet. Again, suggestions are very welcome.
|
175
|
-
|
176
234
|
## Contributing
|
177
235
|
|
178
236
|
1. Fork it ( http://github.com/mtrudel/pragmatic_context/fork )
|
@@ -3,8 +3,6 @@ require 'pragmatic_context/default_contextualizer'
|
|
3
3
|
module PragmaticContext
|
4
4
|
module Contextualizable
|
5
5
|
def Contextualizable.included(base)
|
6
|
-
base.class_eval do
|
7
|
-
end
|
8
6
|
base.extend ClassMethods
|
9
7
|
end
|
10
8
|
|
@@ -30,7 +28,28 @@ module PragmaticContext
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def as_jsonld(opts = nil)
|
33
|
-
|
31
|
+
# We iterate over terms_with_context because we want to look at our own
|
32
|
+
# fields (and not the fields in 'as_json') to case on their class. In the
|
33
|
+
# case where we want to serialize directly, we rely on the field value as
|
34
|
+
# sourced from as_json
|
35
|
+
terms_with_context = self.class.contextualizer.definitions_for_terms(terms).keys
|
36
|
+
json_results = as_json(opts).slice(*terms_with_context)
|
37
|
+
results = {}
|
38
|
+
terms_with_context.each do |term|
|
39
|
+
# Don't use idiomatic case here since Mongoid relations return proxies
|
40
|
+
# that fail the Contextualizable test
|
41
|
+
value = self.send(term)
|
42
|
+
if (value.is_a? Contextualizable)
|
43
|
+
results[term] = self.send(term).as_jsonld
|
44
|
+
elsif (value.is_a? Hash)
|
45
|
+
self.send(term).each do |key, value|
|
46
|
+
results["#{term}:#{key}"] = value
|
47
|
+
end
|
48
|
+
else
|
49
|
+
results[term] = json_results[term]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
results.merge("@context" => context)
|
34
53
|
end
|
35
54
|
|
36
55
|
def context
|
@@ -45,7 +64,7 @@ module PragmaticContext
|
|
45
64
|
private
|
46
65
|
|
47
66
|
def terms
|
48
|
-
|
67
|
+
as_json.keys
|
49
68
|
end
|
50
69
|
end
|
51
70
|
end
|
data/pragmatic_context.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.5"
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_development_dependency "rspec", "~> 2.6"
|
24
|
+
spec.add_development_dependency "guard-rspec"
|
24
25
|
|
25
26
|
spec.add_dependency "activesupport"
|
26
27
|
spec.add_dependency "activemodel"
|
@@ -5,10 +5,10 @@ class Stub
|
|
5
5
|
include ActiveModel::Serializers::JSON
|
6
6
|
include PragmaticContext::Contextualizable
|
7
7
|
|
8
|
-
attr_accessor :bacon
|
8
|
+
attr_accessor :bacon, :ham
|
9
9
|
|
10
10
|
def attributes
|
11
|
-
{ "bacon" => bacon }
|
11
|
+
{ "bacon" => bacon, "ham" => ham }
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -57,12 +57,47 @@ describe PragmaticContext::Contextualizable do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
describe 'as_jsonld' do
|
60
|
-
it 'should respond with
|
60
|
+
it 'should respond with only contextualized terms plus their context' do
|
61
61
|
@contextualizer.stub(:definitions_for_terms) do |terms|
|
62
62
|
{ 'bacon' => { "@id" => "http://bacon.yum" } }.slice(*terms)
|
63
63
|
end
|
64
64
|
subject.bacon = 'crispy'
|
65
|
-
subject.
|
65
|
+
subject.ham = 'honey'
|
66
|
+
subject.as_jsonld.should == { "bacon" => "crispy", "@context" => subject.context }
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should recurse into Contextualizable subobjects' do
|
70
|
+
@contextualizer.stub(:definitions_for_terms) do |terms|
|
71
|
+
{ 'bacon' => { "@id" => "http://bacon.yum" },
|
72
|
+
'ham' => { "@id" => "http://ham.yum" } }.slice(*terms)
|
73
|
+
end
|
74
|
+
subject.bacon = 'crispy'
|
75
|
+
subject.ham = Stub.new
|
76
|
+
subject.ham.bacon = 'nested bacon'
|
77
|
+
subject.ham.ham = 'nested ham'
|
78
|
+
subject.as_jsonld.should == {
|
79
|
+
"@context" => subject.context,
|
80
|
+
"bacon" => "crispy",
|
81
|
+
"ham" => {
|
82
|
+
"@context" => subject.ham.context,
|
83
|
+
"bacon" => "nested bacon",
|
84
|
+
"ham" => "nested ham"
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should compact sub-hashes into namespaced properties on self' do
|
90
|
+
@contextualizer.stub(:definitions_for_terms) do |terms|
|
91
|
+
{ 'bacon' => { "@id" => "http://bacon.yum" },
|
92
|
+
'ham' => { "@id" => "http://ham.yum" } }.slice(*terms)
|
93
|
+
end
|
94
|
+
subject.bacon = 'crispy'
|
95
|
+
subject.ham = { 'bacon' => 'nested bacon' }
|
96
|
+
subject.as_jsonld.should == {
|
97
|
+
"@context" => subject.context,
|
98
|
+
"bacon" => "crispy",
|
99
|
+
"ham:bacon" => "nested bacon"
|
100
|
+
}
|
66
101
|
end
|
67
102
|
end
|
68
103
|
|
@@ -72,14 +107,16 @@ describe PragmaticContext::Contextualizable do
|
|
72
107
|
{ 'bacon' => { "@id" => "http://bacon.yum" } }.slice(*terms)
|
73
108
|
end
|
74
109
|
subject.bacon = 'crispy'
|
110
|
+
subject.ham = 'honey'
|
75
111
|
subject.context['bacon']['@id'].should == 'http://bacon.yum'
|
112
|
+
subject.context['ham'].should == nil
|
76
113
|
end
|
77
114
|
end
|
78
115
|
|
79
116
|
describe 'uncontextualized_terms' do
|
80
117
|
it 'should include terms which are not contextualized by the configured Contextualizer' do
|
81
118
|
@contextualizer.stub(:definitions_for_terms) { {} }
|
82
|
-
subject.uncontextualized_terms.should == ['bacon']
|
119
|
+
subject.uncontextualized_terms.should == ['bacon', 'ham']
|
83
120
|
end
|
84
121
|
end
|
85
122
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pragmatic_context
|
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
|
- Mat Trudel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard-rspec
|
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'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: activesupport
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -90,6 +104,7 @@ files:
|
|
90
104
|
- .gitignore
|
91
105
|
- .rspec
|
92
106
|
- Gemfile
|
107
|
+
- Guardfile
|
93
108
|
- LICENSE.txt
|
94
109
|
- README.md
|
95
110
|
- Rakefile
|
@@ -127,4 +142,3 @@ summary: JSON-LD from a JSON perspective
|
|
127
142
|
test_files:
|
128
143
|
- spec/lib/pragmatic_context/contextualizable_spec.rb
|
129
144
|
- spec/lib/pragmatic_context/default_contextualizer_spec.rb
|
130
|
-
has_rdoc:
|