pragmatic_context 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c7c1851a206e8b77ffbaaae7c8fd88ab89c3e5fe
4
- data.tar.gz: 824579bd6aeda691cd918acb53f5690c47d31b60
3
+ metadata.gz: 40b3f7414a092b590f39f53530c841de2eb6856b
4
+ data.tar.gz: c2690d5363e6ebe4f97d8ff1bf6f74eda15c9d0c
5
5
  SHA512:
6
- metadata.gz: 11801a92e11a66751f968cc97322f6f56fee0695c92c1b3618e7b81bb8f1a2694546ba664f0b11d0ac369d7c1c76777a8aae2bd05289ea060fae3db09a6ee80e
7
- data.tar.gz: 91fdf01fe732d12623c74246b17d8cdd5961fd09effd0487166167ced7ae235b08025507186b502a8993bb43c21ea44b6d518f82eb0196b05bbbb6fa11416b83
6
+ metadata.gz: 4c73f9b9644b5cba0eec15b9057fa38d89a951cfbed66e1e20e6e87fbc3ab30140e1e7cf18930f780b2dd9dd320aaec424a941a23e99d3de6e6a3808b583e171
7
+ data.tar.gz: fdd45f04bd8b81024c96dc441a2b8539d59c77ec32e4a9cbb296a7f3a80a8c21eb6944d7e05d577608f3de4ac88005634c98fbc1cd088ab989ed3d5b3a03681b
data/Guardfile ADDED
@@ -0,0 +1,4 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ end
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' is an embodiment of the abstract idea of a [Family
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
- The `Contextualizable` mixin adds a `context` method to the Person object which
120
- returns a Hash object ready to be serialized into the output object. By wiring
121
- this up in whatever serializer your application uses, you would end up with
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
- as_json(opts).merge("@context" => context)
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
- attributes.keys - ['_id', '_type']
67
+ as_json.keys
49
68
  end
50
69
  end
51
70
  end
@@ -1,3 +1,3 @@
1
1
  module PragmaticContext
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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 the underlying as_json result plus the context' do
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.as_jsonld.should == subject.as_json.merge("@context" => subject.context)
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.2
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-03-28 00:00:00.000000000 Z
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: