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 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: