michael-ken 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +16 -9
- data/README.textile +173 -0
- data/README.txt +34 -6
- data/Rakefile +1 -1
- data/examples/artist.rb +20 -0
- data/lib/ken.rb +17 -2
- data/lib/ken/attribute.rb +52 -0
- data/lib/ken/collection.rb +5 -0
- data/lib/ken/property.rb +56 -2
- data/lib/ken/resource.rb +129 -31
- data/lib/ken/session.rb +0 -2
- data/lib/ken/type.rb +14 -1
- data/lib/ken/util.rb +23 -0
- data/lib/ken/version.rb +1 -1
- data/lib/ken/view.rb +43 -0
- data/spec/fixtures/music_artist.json +102 -0
- data/spec/fixtures/the_police.json +891 -0
- data/spec/integration/ken_spec.rb +34 -0
- data/spec/spec_helper.rb +28 -1
- data/spec/unit/attribute_spec.rb +50 -0
- data/spec/unit/property_spec.rb +30 -0
- data/spec/unit/resource_spec.rb +63 -0
- data/spec/{session_spec.rb → unit/session_spec.rb} +1 -3
- data/spec/unit/type_spec.rb +21 -0
- data/spec/unit/view_spec.rb +26 -0
- data/tasks/gemspec.rb +23 -0
- metadata +16 -7
- data/.gitignore +0 -14
- data/ken.gemspec +0 -32
- data/spec/mql_spec.rb +0 -16
- data/spec/property_spec.rb +0 -0
- data/spec/resource_spec.rb +0 -28
data/Manifest.txt
CHANGED
@@ -1,27 +1,34 @@
|
|
1
|
-
.gitignore
|
2
1
|
History.txt
|
3
2
|
LICENSE
|
4
3
|
Manifest.txt
|
5
|
-
README.txt
|
6
4
|
README.textile
|
5
|
+
README.txt
|
7
6
|
Rakefile
|
8
7
|
TODO
|
9
|
-
|
8
|
+
examples/artist.rb
|
10
9
|
lib/ken.rb
|
10
|
+
lib/ken/attribute.rb
|
11
11
|
lib/ken/collection.rb
|
12
12
|
lib/ken/logger.rb
|
13
13
|
lib/ken/property.rb
|
14
14
|
lib/ken/resource.rb
|
15
15
|
lib/ken/session.rb
|
16
16
|
lib/ken/type.rb
|
17
|
+
lib/ken/util.rb
|
17
18
|
lib/ken/version.rb
|
18
|
-
|
19
|
-
spec/
|
20
|
-
spec/
|
21
|
-
spec/
|
22
|
-
spec/type_spec.rb
|
19
|
+
lib/ken/view.rb
|
20
|
+
spec/fixtures/music_artist.json
|
21
|
+
spec/fixtures/the_police.json
|
22
|
+
spec/integration/ken_spec.rb
|
23
23
|
spec/spec.opts
|
24
24
|
spec/spec_helper.rb
|
25
|
+
spec/unit/attribute_spec.rb
|
26
|
+
spec/unit/property_spec.rb
|
27
|
+
spec/unit/resource_spec.rb
|
28
|
+
spec/unit/session_spec.rb
|
29
|
+
spec/unit/type_spec.rb
|
30
|
+
spec/unit/view_spec.rb
|
31
|
+
tasks/gemspec.rb
|
25
32
|
tasks/hoe.rb
|
26
33
|
tasks/install.rb
|
27
|
-
tasks/spec.rb
|
34
|
+
tasks/spec.rb
|
data/README.textile
ADDED
@@ -0,0 +1,173 @@
|
|
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
|
+
Just born, 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 (that represent the Metaweb Architecture).
|
10
|
+
|
11
|
+
You can navigate the Freebase Graph using a rubyish syntax.
|
12
|
+
|
13
|
+
You should be able to use this Library as a Data Layer (instead of or in addition to
|
14
|
+
ActiveRecord/DataMapper) for your Web Framework of choice (Merb, Rails).
|
15
|
+
|
16
|
+
|
17
|
+
h2. Installation
|
18
|
+
|
19
|
+
Use GitHub RubyGems.
|
20
|
+
|
21
|
+
<pre>
|
22
|
+
<code>
|
23
|
+
$ gem sources -a http://gems.github.com (you only have to do this once)
|
24
|
+
$ sudo gem install michael-ken
|
25
|
+
</code>
|
26
|
+
</pre>
|
27
|
+
|
28
|
+
Or even better, stay on The Edge.
|
29
|
+
|
30
|
+
|
31
|
+
h2. Getting started
|
32
|
+
|
33
|
+
The first place to get started with Freebase is of course, Freebase. Try out their Browser at
|
34
|
+
"http://www.freebase.com":http://www.freebase.com.
|
35
|
+
|
36
|
+
The Freebase Database can be thought of as a huge graph of interconnected nodes that represent
|
37
|
+
knowledge (in a much more structured way than wikipedia does).
|
38
|
+
That graph can be viewed at a higher level through an object-oriented lens which leads to easier interaction.
|
39
|
+
To understand the fundamental Metaweb Architecture please read the official
|
40
|
+
"MQL Reference guide":http://download.freebase.com/MQLReferenceGuide.pdf (with focus on Chapter 2)
|
41
|
+
provided by Freebase.
|
42
|
+
|
43
|
+
In addition, you can learn a lot by employing the Freebase "Query Editor":http://www.freebase.com/tools/queryeditor/.
|
44
|
+
|
45
|
+
h3. Fetching a Resource
|
46
|
+
|
47
|
+
Let's ask Ken what he knows about the British Band New Order.
|
48
|
+
|
49
|
+
<pre>
|
50
|
+
<code>
|
51
|
+
resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
|
52
|
+
</code>
|
53
|
+
</pre>
|
54
|
+
|
55
|
+
h3. Inspecting the types
|
56
|
+
|
57
|
+
Every Resource can have multiple types.
|
58
|
+
|
59
|
+
<pre>
|
60
|
+
<code>
|
61
|
+
resource.types
|
62
|
+
# => [ #<Type id="/film/music_contributor" name="Film music contributor">, #<Type id="/music/artist" name="Musical Artist">,
|
63
|
+
#<Type id="/common/topic" name="Topic">, #<Type id="/music/musical_group" name="Musical Group">,
|
64
|
+
#<Type id="/broadcast/artist" name="Broadcast Artist">, #<Type id="/music/group_member" name="Musical Group Member"> ]
|
65
|
+
</code>
|
66
|
+
</pre>
|
67
|
+
|
68
|
+
We can see that New Order is a member of Music Artist, Film Music Contributor, Broadcast Artist and other types.
|
69
|
+
|
70
|
+
h3. Inspecting a types properties
|
71
|
+
|
72
|
+
A type defines a set of properties to describe a Resource.
|
73
|
+
|
74
|
+
<pre>
|
75
|
+
<code>
|
76
|
+
resource.types.each do |type|
|
77
|
+
type.properties # => e.g. [ #<Property id="/music/musical_group/member"> ]
|
78
|
+
end
|
79
|
+
</code>
|
80
|
+
</pre>
|
81
|
+
|
82
|
+
We get sets of Properties for each Type. The Type Musical Group has just one Property @/music/musical_group/member@
|
83
|
+
named Members Of Musical Group.
|
84
|
+
|
85
|
+
h4. Listing all Attributes
|
86
|
+
|
87
|
+
After inspecting a Resource's Types and Properties we now know what we could know. But actually we don't know nothing :)
|
88
|
+
So it's time to ask for the values of properties, the so called _Attributes_.
|
89
|
+
|
90
|
+
~Note: In Ken's terminology we differ between _Properties_ and concrete Property instances, the _Attributes_, while
|
91
|
+
Freebase itself doesn't.~
|
92
|
+
|
93
|
+
<pre>
|
94
|
+
<code>
|
95
|
+
resource.attributes.each do |att|
|
96
|
+
att # => e.g. #<Attribute property="/music/artist/album">
|
97
|
+
att.property.name # => e.g. "Albums"
|
98
|
+
|
99
|
+
att.values
|
100
|
+
# e.g. => [ #<Resource id="/guid/9202a8c04000641f8000000002fa2556" name="Ceremony">,
|
101
|
+
#<Resource id="/guid/9202a8c04000641f8000000002fa24d5" name="Procession">,
|
102
|
+
#<Resource id="/guid/9202a8c04000641f8000000002fa20d3" name="Everything's Gone Green">, ... ]
|
103
|
+
# e.g. => ["1980"]
|
104
|
+
end
|
105
|
+
</code>
|
106
|
+
</pre>
|
107
|
+
|
108
|
+
Attributes are slightly more complicated to handle compared to Types and Properties.
|
109
|
+
|
110
|
+
There are four kinds of Attributes.
|
111
|
+
* Unique Value Type
|
112
|
+
* Unique Object Type
|
113
|
+
* Non-unique Value Type
|
114
|
+
* Non-unique Object
|
115
|
+
|
116
|
+
In order to be able to use unique and non-unique Attributes in the same manner we always wrap the value of an Attribute
|
117
|
+
in a Collection, no matter if there's one value or there are many.
|
118
|
+
|
119
|
+
h4. Group Attributes by their Type using Views
|
120
|
+
|
121
|
+
|
122
|
+
<pre>
|
123
|
+
<code>
|
124
|
+
resource.views.each do |view|
|
125
|
+
view # => e.g. #<View type="/music/artist">
|
126
|
+
view.type # => e.g #<Type id="/music/artist" name="Musical Artist">
|
127
|
+
view.attributes
|
128
|
+
# => [#<Attribute property="/music/artist/home_page">, #<Attribute property="/music/artist/genre">,
|
129
|
+
#<Attribute property="/music/artist/active_start">, #<Attribute property="/music/artist/similar_artist">,
|
130
|
+
#<Attribute property="/music/artist/album">, #<Attribute property="/music/artist/label">,
|
131
|
+
#<Attribute property="/music/artist/track">, #<Attribute property="/music/artist/origin">]
|
132
|
+
|
133
|
+
view.attributes.each do |att|
|
134
|
+
att.values
|
135
|
+
# e.g. => [ #<Resource id="/en/alternative_dance" name="Alternative dance">,
|
136
|
+
#<Resource id="/en/synthpop" name="Synthpop">,
|
137
|
+
#<Resource id="/en/house_music" name="House music">,
|
138
|
+
#<Resource id="/en/post-punk" name="Post-punk"> ]
|
139
|
+
# e.g. => ["1980"]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
</code>
|
143
|
+
</pre>
|
144
|
+
|
145
|
+
h2. Status
|
146
|
+
|
147
|
+
Currently, the focus lies on inspecting Freebase Resources in a generic way. That's why
|
148
|
+
there is no support for accessing Properties or Attributes directly when you know them already.
|
149
|
+
That keeps me focussed and prevents me from adding too much sugar.
|
150
|
+
|
151
|
+
Therefore I would say that the first application using Ken will definitely be a Browser Application. :)
|
152
|
+
|
153
|
+
If you rather want to query based on Types and access Properties/Attributes directly you should consider using
|
154
|
+
Chris "Eppsteins Freebase Library":http://github.com/chriseppstein/freebase/tree/master instead.
|
155
|
+
|
156
|
+
h3. Features
|
157
|
+
|
158
|
+
* Fetching of single Resources
|
159
|
+
* Type inspection
|
160
|
+
* Attributes inspection
|
161
|
+
* Views on Resources to group Attributes based on the Resource's types
|
162
|
+
* Some specs
|
163
|
+
|
164
|
+
h3. Roadmap
|
165
|
+
|
166
|
+
# Much more specs
|
167
|
+
# Support for querying of multiple Resources
|
168
|
+
# Better Type Support
|
169
|
+
# API for Set Based Browsing (see http://mqlx.com/~david/parallax/)
|
170
|
+
# Accessing Properties/Attributes directly (e.g. resource.genres )
|
171
|
+
# Write-Support
|
172
|
+
|
173
|
+
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
CHANGED
@@ -1,26 +1,54 @@
|
|
1
|
-
=
|
1
|
+
= Ken
|
2
2
|
|
3
3
|
* http://www.github.com/michael/ken
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
|
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
|
+
|
8
18
|
|
9
19
|
== FEATURES/PROBLEMS:
|
10
20
|
|
11
|
-
|
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
|
12
37
|
|
13
38
|
== SYNOPSIS:
|
14
39
|
|
15
|
-
|
40
|
+
resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
|
16
41
|
|
17
42
|
== REQUIREMENTS:
|
18
43
|
|
19
|
-
|
44
|
+
- Ruby >=1.8.x
|
45
|
+
- RubyGems >=1.2.x
|
46
|
+
- Extlib >=0.9.x
|
20
47
|
|
21
48
|
== INSTALL:
|
22
49
|
|
23
|
-
|
50
|
+
$ gem sources -a http://gems.github.com (you only have to do this once)
|
51
|
+
$ sudo gem install michael-ken
|
24
52
|
|
25
53
|
== LICENSE:
|
26
54
|
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ require ROOT + 'lib/ken/version'
|
|
11
11
|
AUTHOR = 'Michael Aufreiter'
|
12
12
|
EMAIL = 'ma[at]zive[dot]at'
|
13
13
|
GEM_NAME = 'ken'
|
14
|
-
GEM_VERSION = '0.0.
|
14
|
+
GEM_VERSION = '0.0.2'# Ken::VERSION
|
15
15
|
GEM_DEPENDENCIES = [
|
16
16
|
[ 'extlib', '>=0.9.10' ]
|
17
17
|
# [ 'addressable', '~>2.0.1' ]
|
data/examples/artist.rb
ADDED
@@ -0,0 +1,20 @@
|
|
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::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
|
8
|
+
|
9
|
+
resource = Ken.get('/en/the_police')
|
10
|
+
|
11
|
+
resource.views.each do |view|
|
12
|
+
puts view
|
13
|
+
puts "==============================="
|
14
|
+
view.attributes.each do |a|
|
15
|
+
puts a.property
|
16
|
+
puts "----------------"
|
17
|
+
puts a
|
18
|
+
puts # newline
|
19
|
+
end
|
20
|
+
end
|
data/lib/ken.rb
CHANGED
@@ -8,9 +8,12 @@ require 'addressable/uri'
|
|
8
8
|
dir = Pathname(__FILE__).dirname.expand_path + 'ken'
|
9
9
|
|
10
10
|
require dir + 'version'
|
11
|
+
require dir + 'util'
|
11
12
|
require dir + 'resource'
|
12
13
|
require dir + 'type'
|
14
|
+
require dir + 'view'
|
13
15
|
require dir + 'property'
|
16
|
+
require dir + 'attribute'
|
14
17
|
require dir + 'collection'
|
15
18
|
require dir + 'session'
|
16
19
|
require dir + 'logger'
|
@@ -18,13 +21,22 @@ require dir + 'logger'
|
|
18
21
|
# init logger as soon as the library is required
|
19
22
|
Ken::Logger.new(STDOUT, :error)
|
20
23
|
|
24
|
+
# init default session
|
25
|
+
Ken::Session.new('http://www.freebase.com', 'ma', 'xxxxx')
|
21
26
|
|
22
27
|
module Ken
|
23
28
|
def self.all(options = {})
|
24
|
-
#raise ArgumentError.new("must be a hash") unless options.is_a(::Hash)
|
29
|
+
# raise ArgumentError.new("must be a hash") unless options.is_a(::Hash)
|
25
30
|
raise NotImplementedError
|
26
31
|
end
|
27
32
|
|
33
|
+
|
34
|
+
# Executes an Mql Query against the Freebase API and returns the result wrapped
|
35
|
+
# in a <tt>Resource</tt> Object.
|
36
|
+
#
|
37
|
+
# == Examples
|
38
|
+
#
|
39
|
+
# Ken.get('/en/the_police') => #<Resource id="/en/the_police" name="The Police">
|
28
40
|
def self.get(id)
|
29
41
|
# TODO check if it has a correct /type/object/id syntax
|
30
42
|
raise ArgumentError.new("must be a string") unless id.is_a?(::String)
|
@@ -38,7 +50,10 @@ module Ken
|
|
38
50
|
:properties => [{
|
39
51
|
:id => nil,
|
40
52
|
:name => nil,
|
41
|
-
:expected_type => nil
|
53
|
+
:expected_type => nil,
|
54
|
+
:unique => nil,
|
55
|
+
:reverse_property => nil,
|
56
|
+
:master_property => nil,
|
42
57
|
}]
|
43
58
|
}]
|
44
59
|
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Ken
|
2
|
+
class Attribute
|
3
|
+
attr_reader :property
|
4
|
+
|
5
|
+
# initializes a resource by json result
|
6
|
+
def initialize(data, property)
|
7
|
+
raise "error" unless data.kind_of?(Array)
|
8
|
+
|
9
|
+
@data = data
|
10
|
+
@property = property # belongs to a property
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.create(data, property)
|
15
|
+
Ken::Attribute.new(data, property)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api public
|
19
|
+
def to_s
|
20
|
+
subject.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api public
|
24
|
+
def inspect
|
25
|
+
result = "#<Attribute property=\"#{property.id || "nil"}\">"
|
26
|
+
end
|
27
|
+
|
28
|
+
# returns just the subject
|
29
|
+
def values
|
30
|
+
subject
|
31
|
+
end
|
32
|
+
|
33
|
+
def unique?
|
34
|
+
@property.unique?
|
35
|
+
end
|
36
|
+
|
37
|
+
def object_type?
|
38
|
+
@property.object_type?
|
39
|
+
end
|
40
|
+
|
41
|
+
# is this a good idea? using the values method seems more natural to me
|
42
|
+
# def method_missing(name, *args, &block)
|
43
|
+
# subject.send(name, *args, &block)
|
44
|
+
# end
|
45
|
+
|
46
|
+
# initializes the subject if used the first time
|
47
|
+
private
|
48
|
+
def subject
|
49
|
+
@subject ||= Ken::Collection.new(@data.map { |r| object_type? ? Ken::Resource.new(r) : r["value"] })
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/ken/collection.rb
CHANGED
data/lib/ken/property.rb
CHANGED
@@ -4,24 +4,78 @@ module Ken
|
|
4
4
|
# initializes a resource by json result
|
5
5
|
def initialize(data, type)
|
6
6
|
raise "error" unless data.kind_of?(Hash)
|
7
|
-
|
8
7
|
@data = data
|
9
8
|
@type = type
|
10
9
|
self
|
11
10
|
end
|
12
11
|
|
12
|
+
# @api public
|
13
13
|
def id
|
14
14
|
@data["id"]
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
|
+
# @api public
|
17
18
|
def name
|
18
19
|
@data["name"]
|
19
20
|
end
|
20
21
|
|
22
|
+
# @api public
|
23
|
+
def to_s
|
24
|
+
name || id || ""
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api public
|
28
|
+
def inspect
|
29
|
+
result = "#<Property id=\"#{id}\" expected_type=\"#{expected_type || "nil"}\" unique=\"#{unique?}\" object_type=\"#{object_type?}\">"
|
30
|
+
end
|
31
|
+
|
32
|
+
# returns the type of which the property is a part of
|
33
|
+
# every property always has exactly one type.
|
34
|
+
# that's why /type/property/schema is a unique property
|
35
|
+
# @api public
|
21
36
|
def type
|
22
37
|
@type
|
23
38
|
end
|
24
39
|
|
40
|
+
# @api public
|
41
|
+
def reverse_property
|
42
|
+
@data["reverse_property"]
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api public
|
46
|
+
def master_property
|
47
|
+
@data["master_property"]
|
48
|
+
end
|
49
|
+
|
50
|
+
# returns true if the property is unique
|
51
|
+
# @api public
|
52
|
+
def unique?
|
53
|
+
return @data["unique"]==true
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns true if the property is an object type
|
57
|
+
# @api public
|
58
|
+
def object_type?
|
59
|
+
!%w{
|
60
|
+
/type/id
|
61
|
+
/type/int
|
62
|
+
/type/float
|
63
|
+
/type/boolean
|
64
|
+
/type/text
|
65
|
+
/type/rawstring
|
66
|
+
/type/uri
|
67
|
+
/type/datetime
|
68
|
+
/type/key
|
69
|
+
}.include?(expected_type)
|
70
|
+
end
|
71
|
+
|
72
|
+
# returns true if the property is a value type
|
73
|
+
# @api public
|
74
|
+
def value_type?
|
75
|
+
!object_type?
|
76
|
+
end
|
77
|
+
|
78
|
+
# @api public
|
25
79
|
def expected_type
|
26
80
|
@data["expected_type"]
|
27
81
|
end
|