adamsalter-ken 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ test_log
2
+ pkg
3
+ pkg/*
4
+ */pkg/*
5
+ bundle
6
+ bundle/*
7
+ doc
8
+ *.log
9
+ log
10
+ !log*.rb
11
+ */log
12
+ log/*
13
+ */log/*
14
+ coverage
15
+ */coverage
16
+ lib/dm-more.rb
17
+ *.db
18
+ nbproject
19
+ .DS_Store
20
+ rspec_report.html
21
+ *.swp
22
+ _Yardoc
23
+ */ri
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ === 0.0.1 / not released
2
+
3
+ * Birthday!
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Aufreiter
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,264 @@
1
+ h1. Ken
2
+
3
+ h2. Introduction
4
+
5
+ Ken is a Data Layer for Knowledge Representation.
6
+
7
+ It's being built to access the Metaweb Services supplied by Freebase.com.
8
+ The project’s goals are the provision of a concise API for querying and writing.
9
+ Therefore it wraps the Metaweb Architecture to smart Ruby Objects.
10
+
11
+ You can navigate the Freebase Graph using a rubyish syntax.
12
+ Also you can use this library as a Data Layer (instead of or in addition to ActiveRecord/DataMapper) for your Web Framework of choice (Merb, Rails).
13
+
14
+ h2. Installation
15
+
16
+ Use GitHub RubyGems:
17
+
18
+ <pre>
19
+ <code>
20
+ $ gem sources -a http://gems.github.com (you only have to do this once)
21
+ $ sudo gem install michael-ken
22
+ </code>
23
+ </pre>
24
+
25
+ In your Ruby files add:
26
+
27
+ <pre>
28
+ <code>
29
+ require 'rubygems'
30
+ gem 'michael-ken'
31
+ require 'ken'
32
+ </code>
33
+ </pre>
34
+
35
+
36
+ h2. Getting started
37
+
38
+ The first place to get started with Freebase is of course, Freebase. Try out their Browser at
39
+ "http://www.freebase.com":http://www.freebase.com.
40
+
41
+ The Freebase Database can be thought of as a huge graph of interconnected nodes that represent
42
+ knowledge (in a much more structured way than wikipedia does).
43
+ That graph can be viewed at a higher level through an object-oriented lens which leads to easier interaction.
44
+ To understand the fundamental Metaweb Architecture please read the official
45
+ "MQL Reference guide":http://download.freebase.com/MQLReferenceGuide.pdf (with focus on Chapter 2)
46
+ provided by Freebase.
47
+
48
+ In addition, you can learn a lot by employing the Freebase "Query Editor":http://www.freebase.com/tools/queryeditor/.
49
+
50
+ h3. Fetching a Resource
51
+
52
+ Let's ask Ken what he knows about the British Band New Order.
53
+
54
+ <pre>
55
+ <code>
56
+ resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
57
+ </code>
58
+ </pre>
59
+
60
+ h3. Inspecting the Types
61
+
62
+ Every Resource can have multiple types.
63
+
64
+ <pre>
65
+ <code>
66
+ resource.types
67
+ # => [ #<Type id="/film/music_contributor" name="Film music contributor">, #<Type id="/music/artist" name="Musical Artist">,
68
+ #<Type id="/common/topic" name="Topic">, #<Type id="/music/musical_group" name="Musical Group">,
69
+ #<Type id="/broadcast/artist" name="Broadcast Artist">, #<Type id="/music/group_member" name="Musical Group Member"> ]
70
+ </code>
71
+ </pre>
72
+
73
+ We can see that New Order is a member of Music Artist, Film Music Contributor, Broadcast Artist and other types.
74
+
75
+ h3. Inspecting a Type's properties
76
+
77
+ A type defines a set of properties to describe a Resource.
78
+
79
+ <pre>
80
+ <code>
81
+ resource.types.each do |type|
82
+ type.properties # => e.g. [ #<Property id="/music/musical_group/member"> ]
83
+ end
84
+ </code>
85
+ </pre>
86
+
87
+ We get sets of Properties for each Type. The Type Musical Group has just one Property @/music/musical_group/member@
88
+ named Members Of Musical Group.
89
+
90
+ h3. Listing all Attributes
91
+
92
+ After inspecting a Resource's Types and Properties we now know what we could know. But actually we don't know nothing :)
93
+ So it's time to ask for the values of properties, the so called _Attributes_.
94
+
95
+ ~Note: In Ken's terminology we differ between _Properties_ and concrete Property instances, the _Attributes_, while
96
+ Freebase itself doesn't.~
97
+
98
+ <pre>
99
+ <code>
100
+ resource.attributes.each do |att|
101
+ att # => e.g. #<Attribute property="/music/artist/album">
102
+ att.property.name # => e.g. "Albums"
103
+
104
+ att.values
105
+ # e.g. => [ #<Resource id="/guid/9202a8c04000641f8000000002fa2556" name="Ceremony">,
106
+ #<Resource id="/guid/9202a8c04000641f8000000002fa24d5" name="Procession">,
107
+ #<Resource id="/guid/9202a8c04000641f8000000002fa20d3" name="Everything's Gone Green">, ... ]
108
+ # e.g. => ["1980"]
109
+ end
110
+ </code>
111
+ </pre>
112
+
113
+ Attributes are slightly more complicated to handle compared to Types and Properties.
114
+
115
+ There are four kinds of Attributes.
116
+ * Unique Value Type
117
+ * Unique Object Type
118
+ * Non-unique Value Type
119
+ * Non-unique Object
120
+
121
+ In order to be able to use unique and non-unique Attributes in the same manner we always wrap the value of an Attribute
122
+ in a Collection, no matter if there's one value or there are many.
123
+
124
+ h3. Group Attributes by their Type using Views
125
+
126
+
127
+ <pre>
128
+ <code>
129
+ resource.views.each do |view|
130
+ view # => e.g. #<View type="/music/artist">
131
+ view.type # => e.g #<Type id="/music/artist" name="Musical Artist">
132
+ view.attributes
133
+ # => [#<Attribute property="/music/artist/home_page">, #<Attribute property="/music/artist/genre">,
134
+ #<Attribute property="/music/artist/active_start">, #<Attribute property="/music/artist/similar_artist">,
135
+ #<Attribute property="/music/artist/album">, #<Attribute property="/music/artist/label">,
136
+ #<Attribute property="/music/artist/track">, #<Attribute property="/music/artist/origin">]
137
+
138
+ view.attributes.each do |att|
139
+ att.values
140
+ # e.g. => [ #<Resource id="/en/alternative_dance" name="Alternative dance">,
141
+ #<Resource id="/en/synthpop" name="Synthpop">,
142
+ #<Resource id="/en/house_music" name="House music">,
143
+ #<Resource id="/en/post-punk" name="Post-punk"> ]
144
+ # e.g. => ["1980"]
145
+ end
146
+ end
147
+ </code>
148
+ </pre>
149
+
150
+ h3. Fetching multiple Resources using a query
151
+
152
+ As of now you can ask for multiple Resources by specifying a query.
153
+
154
+ <pre>
155
+ <code>
156
+ resources = Ken.all(:name => "Apple", :type => "/music/album")
157
+ # => [#<Resource id="/guid/9202a8c04000641f80000000031dae7c" name="Apple">,
158
+ #<Resource id="/guid/9202a8c04000641f8000000007ce31ec" name="Apple">]
159
+ </code>
160
+ </pre>
161
+
162
+ Keep in mind that only the top level of the query is mapped to a Collection of Resource Objects.
163
+ So asking for values in a nested level does not make sense. Use nested statements just for
164
+ lowering the top level result.
165
+
166
+ However you can instead navigate the normal way to figure out that values.
167
+ _But won't that require another query to triggered? Certainly._
168
+
169
+ Let's look at a nested query:
170
+
171
+ <pre>
172
+ <code>
173
+ query = {
174
+ :directed_by => "George Lucas",
175
+ :starring => [
176
+ {
177
+ :actor => "Harrison Ford"
178
+ }
179
+ ],
180
+ :type => "/film/film"
181
+ }
182
+
183
+ resources = Ken.all(query)
184
+ # => [#<Resource id="/en/star_wars_episode_iv_a_new_hope" name="Star Wars Episode IV: A New Hope">,
185
+ #<Resource id="/en/american_graffiti" name="American Graffiti">,
186
+ #<Resource id="/en/the_star_wars_holiday_special" name="The Star Wars Holiday Special">]
187
+ </code>
188
+ </pre>
189
+
190
+ h3. Access properties attributes directly
191
+
192
+ Ken is primarily designed for inspecting resources in a generic way, what's ideal for domain independent browsing applications.
193
+ However, there are legitimate situations where you already know what you want to access.
194
+
195
+ That's why I now added direct Property/Attribute access, but only on a Type/View level:
196
+
197
+ <pre>
198
+ <code>
199
+ resource = Ken.get('/en/new_order')
200
+ type = resource.types[1] # => #<Type id="/music/artist" name="Musical Artist">
201
+ # because we know _/music/artist_ has a _genre_ property we can access that directly
202
+ type.genre # => #<Property id="/music/artist/genre" expected_type="/music/genre" unique="false" object_type="true">
203
+ </code>
204
+ </pre>
205
+
206
+ The same works for views:
207
+
208
+ <pre>
209
+ <code>
210
+ resource = Ken.get('/en/new_order')
211
+ view = resource.views[1] # => #<View type="/music/artist">
212
+ # because we know _/music/artist_ has a _genre_ property we can access attribute directly as well
213
+ view.genre # => #<Attribute property="/music/artist/genre">
214
+ </code>
215
+ </pre>
216
+
217
+ If you rather want to query based on Types and access Properties/Attributes directly you can consider using
218
+ Chris "Eppsteins Freebase Library":http://github.com/chriseppstein/freebase/tree/master as an alternative.
219
+
220
+
221
+ h3. Low Level API
222
+
223
+ Sometimes you may want to do specific queries instead of inspecting Resources as a whole.
224
+ In such a case you would want to use Ken's low level API.
225
+
226
+ _mqlread_ works like the regular _mqlread service_, except that you are able to pass ruby hashes instead of JSON.
227
+ And you don't have to deal with HTTP, parameter encoding and parsing JSON.
228
+
229
+ <pre>
230
+ <code>
231
+ artists = Ken.session.mqlread([{
232
+ :type => "/music/artist",
233
+ :id => nil,
234
+ :"/common/topic/webpage" => [{:uri => nil}],
235
+ :home_page => [{:uri => nil}],
236
+ :limit => 2
237
+ }])
238
+
239
+ # => [
240
+ {"type"=>"/music/artist", "home_page"=>[{"uri"=>"http://www.massiveattack.co.uk/"}], "id"=>"/en/massive_attack", "/common/topic/webpage"=>[{"uri"=>"http://musicmoz.org/Bands_and_Artists/M/Massive_Attack/"}, {"uri"=>"http://www.discogs.com/artist/Massive+Attack"}, {"uri"=>"http://www.massiveattackarea.com/"}, {"uri"=>"http://www.massiveattack.co.uk/"}, {"uri"=>"http://www.massiveattack.com/"}]},
241
+ {"type"=>"/music/artist", "home_page"=>[{"uri"=>"http://www.apartment26.com/"}], "id"=>"/en/apartment_26", "/common/topic/webpage"=>[{"uri"=>"http://www.discogs.com/artist/Apartment+26"}, {"uri"=>"http://musicmoz.org/Bands_and_Artists/A/Apartment_26/"}, {"uri"=>"http://www.apartment26.com/"}]}
242
+ ]
243
+ </code>
244
+ </pre>
245
+
246
+ h2. Project Status
247
+
248
+ h3. Features
249
+
250
+ * Fetching of single Resources
251
+ * Fetching of multiple Resources by specifying a query
252
+ * Accessing Properties/Attributes directly (on a type/view level)
253
+ * Type inspection
254
+ * Attribute inspection
255
+ * Low Level API (mqlread)
256
+ * Rails and Merb support
257
+ * Views on Resources to group Attributes based on the Resource's types
258
+
259
+ h3. Roadmap
260
+
261
+ # More tests
262
+ # Write-Support
263
+
264
+ Initial thoughts, obviously not up-to-date and not conforming to the current version, are available at "http://wiki.github.com/michael/ken":http://wiki.github.com/michael/ken.
data/README.txt ADDED
@@ -0,0 +1,76 @@
1
+ = Ken
2
+
3
+ * http://www.github.com/michael/ken
4
+
5
+ == DESCRIPTION:
6
+
7
+ Ken is a Data Layer for Knowledge Representation.
8
+
9
+ It's being built to access the Metaweb Services supplied by Freebase.com.
10
+ Just born, the project’s goals are the provision of a concise API for querying and writing.
11
+ Therefore it wraps the Metaweb Architecture to smart Ruby Objects (that represent the Metaweb Architecture).
12
+
13
+ You can navigate the Freebase Graph using a rubyish syntax.
14
+
15
+ You should be able to use this Library as a Data Layer (instead of or in addition to
16
+ ActiveRecord/DataMapper) for your Web Framework of choice (Merb, Rails).
17
+
18
+
19
+ == FEATURES/PROBLEMS:
20
+
21
+ Features
22
+
23
+ * Fetching of single Resources
24
+ * Type inspection
25
+ * Attributes inspection
26
+ * Views on Resources to group Attributes based on the Resource's types
27
+ * Some specs
28
+
29
+ Roadmap
30
+
31
+ 1. Much more specs
32
+ 2. Support for querying of multiple Resources
33
+ 3. Better Type Support
34
+ 4. API for Set Based Browsing (see http://mqlx.com/~david/parallax/)
35
+ 5. Accessing Properties/Attributes directly (e.g. resource.genres )
36
+ 6. Write-Support
37
+
38
+ == SYNOPSIS:
39
+
40
+ resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
41
+
42
+ == REQUIREMENTS:
43
+
44
+ - Ruby >=1.8.x
45
+ - RubyGems >=1.2.x
46
+ - Extlib >=0.9.x
47
+
48
+ == INSTALL:
49
+
50
+ $ gem sources -a http://gems.github.com (you only have to do this once)
51
+ $ sudo gem install michael-ken
52
+
53
+ == LICENSE:
54
+
55
+ (The MIT License)
56
+
57
+ Copyright (c) 2009 Michael Aufreiter
58
+
59
+ Permission is hereby granted, free of charge, to any person obtaining
60
+ a copy of this software and associated documentation files (the
61
+ 'Software'), to deal in the Software without restriction, including
62
+ without limitation the rights to use, copy, modify, merge, publish,
63
+ distribute, sublicense, and/or sell copies of the Software, and to
64
+ permit persons to whom the Software is furnished to do so, subject to
65
+ the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be
68
+ included in all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
71
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
74
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
75
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
76
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ken"
8
+ gem.summary = %Q{Ruby API for Accessing the Freebase}
9
+ gem.email = "ma[at]zive[dot]at"
10
+ gem.homepage = "http://github.com/michael/ken"
11
+ gem.authors = ["michael"]
12
+ gem.add_dependency('extlib')
13
+ gem.add_dependency('json')
14
+ gem.add_dependency('addressable')
15
+ # gem.files = FileList["[A-Z]*.*"]
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/*_test.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ if File.exist?('VERSION.yml')
48
+ config = YAML.load(File.read('VERSION.yml'))
49
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
50
+ else
51
+ version = ""
52
+ end
53
+
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "ken #{version}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
data/TODO ADDED
File without changes
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,21 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+
4
+ EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
5
+ require EXAMPLES_ROOT.parent + 'lib/ken'
6
+
7
+ Ken::Logger.new(STDOUT, :info)
8
+ Ken::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
9
+
10
+ resource = Ken.get('/en/the_police')
11
+
12
+ resource.views.each do |view|
13
+ puts view
14
+ puts "="*20
15
+ view.attributes.each do |a|
16
+ puts a.property
17
+ puts "-"*20
18
+ puts a
19
+ puts # newline
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+
4
+ # displays all links related to music/artists
5
+ # low level api through Ken.session.mqlread is used here
6
+
7
+ EXAMPLES_ROOT = Pathname(__FILE__).dirname.expand_path
8
+ require EXAMPLES_ROOT.parent + 'lib/ken'
9
+
10
+ Ken::Session.new('http://www.freebase.com', 'ma', '*****')
11
+
12
+ artists = Ken.session.mqlread([{
13
+ :type => "/music/artist",
14
+ :id => nil,
15
+ :"/common/topic/webpage" => [{:uri => nil}],
16
+ :home_page => [{:uri => nil}],
17
+ :limit => 50
18
+ }])
19
+
20
+ artists.each do |artist|
21
+ artist["/common/topic/webpage"].each do |webpage|
22
+ puts webpage["uri"]
23
+ end
24
+
25
+ artist["home_page"].each do |homepage|
26
+ puts homepage["uri"]
27
+ end
28
+ end
data/ken.gemspec ADDED
@@ -0,0 +1,88 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ken}
5
+ s.version = "0.1.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["michael"]
9
+ s.date = %q{2009-08-12}
10
+ s.email = %q{ma[at]zive[dot]at}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.textile",
14
+ "README.txt"
15
+ ]
16
+ s.files = [
17
+ ".gitignore",
18
+ "History.txt",
19
+ "LICENSE",
20
+ "README.textile",
21
+ "README.txt",
22
+ "Rakefile",
23
+ "TODO",
24
+ "VERSION",
25
+ "examples/artist.rb",
26
+ "examples/artist_links.rb",
27
+ "ken.gemspec",
28
+ "lib/ken.rb",
29
+ "lib/ken/attribute.rb",
30
+ "lib/ken/collection.rb",
31
+ "lib/ken/logger.rb",
32
+ "lib/ken/property.rb",
33
+ "lib/ken/resource.rb",
34
+ "lib/ken/session.rb",
35
+ "lib/ken/type.rb",
36
+ "lib/ken/util.rb",
37
+ "lib/ken/view.rb",
38
+ "rails/init.rb",
39
+ "tasks/ken.rb",
40
+ "tasks/spec.rb",
41
+ "test/fixtures/music_artist.json",
42
+ "test/fixtures/the_police.json",
43
+ "test/integration/ken_test.rb",
44
+ "test/test_helper.rb",
45
+ "test/unit/attribute_test.rb",
46
+ "test/unit/property_test.rb",
47
+ "test/unit/resource_test.rb",
48
+ "test/unit/session_test.rb",
49
+ "test/unit/type_test.rb",
50
+ "test/unit/view_test.rb"
51
+ ]
52
+ s.homepage = %q{http://github.com/michael/ken}
53
+ s.rdoc_options = ["--charset=UTF-8"]
54
+ s.require_paths = ["lib"]
55
+ s.rubygems_version = %q{1.3.4}
56
+ s.summary = %q{Ruby API for Accessing the Freebase}
57
+ s.test_files = [
58
+ "test/integration/ken_test.rb",
59
+ "test/test_helper.rb",
60
+ "test/unit/attribute_test.rb",
61
+ "test/unit/property_test.rb",
62
+ "test/unit/resource_test.rb",
63
+ "test/unit/session_test.rb",
64
+ "test/unit/type_test.rb",
65
+ "test/unit/view_test.rb",
66
+ "examples/artist.rb",
67
+ "examples/artist_links.rb"
68
+ ]
69
+
70
+ if s.respond_to? :specification_version then
71
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
72
+ s.specification_version = 3
73
+
74
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
75
+ s.add_runtime_dependency(%q<extlib>, [">= 0"])
76
+ s.add_runtime_dependency(%q<json>, [">= 0"])
77
+ s.add_runtime_dependency(%q<addressable>, [">= 0"])
78
+ else
79
+ s.add_dependency(%q<extlib>, [">= 0"])
80
+ s.add_dependency(%q<json>, [">= 0"])
81
+ s.add_dependency(%q<addressable>, [">= 0"])
82
+ end
83
+ else
84
+ s.add_dependency(%q<extlib>, [">= 0"])
85
+ s.add_dependency(%q<json>, [">= 0"])
86
+ s.add_dependency(%q<addressable>, [">= 0"])
87
+ end
88
+ end
@@ -0,0 +1,62 @@
1
+ module Ken
2
+ class Attribute
3
+
4
+ include Extlib::Assertions
5
+ attr_reader :property
6
+
7
+ # initializes a resource by json result
8
+ def initialize(data, property)
9
+ assert_kind_of 'data', data, Array
10
+ assert_kind_of 'property', property, Ken::Property
11
+ @data, @property = data, property
12
+ end
13
+
14
+ # factory method for creating an attribute instance
15
+ # @api semipublic
16
+ def self.create(data, property)
17
+ Ken::Attribute.new(data, property)
18
+ end
19
+
20
+ # @api public
21
+ def to_s
22
+ subject.to_s
23
+ end
24
+
25
+ # @api public
26
+ def inspect
27
+ result = "#<Attribute property=\"#{property.id || "nil"}\">"
28
+ end
29
+
30
+ # returns a collection of values
31
+ # in case of a unique property the array holds just one value
32
+ # @api public
33
+ def values
34
+ subject
35
+ end
36
+
37
+ # unique properties can have at least one value
38
+ # @api public
39
+ def unique?
40
+ @property.unique?
41
+ end
42
+
43
+ # object type properties always link to resources
44
+ # @api public
45
+ def object_type?
46
+ @property.object_type?
47
+ end
48
+
49
+ # returns true if the property is a value type
50
+ # value type properties refer to simple values like /type/text
51
+ # @api public
52
+ def value_type?
53
+ @property.value_type?
54
+ end
55
+
56
+ private
57
+ # initializes the subject if used for the first time
58
+ def subject
59
+ @subject ||= Ken::Collection.new(@data.map { |r| object_type? ? Ken::Resource.new(r) : r["value"] })
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,8 @@
1
+ module Ken
2
+ class Collection < Array
3
+ # add a linebreak after each entry
4
+ def to_s
5
+ self.inject("") { |m,i| "#{m}#{i.to_s}\n"}
6
+ end
7
+ end
8
+ end