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 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
- ken.gemspec
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
- spec/mql_spec.rb
19
- spec/property_spec.rb
20
- spec/resource_spec.rb
21
- spec/session_spec.rb
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
- = Mql
1
+ = Ken
2
2
 
3
3
  * http://www.github.com/michael/ken
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- FIX (describe your package)
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
- * FIX (list of features or problems)
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
- FIX (code sample of usage)
40
+ resource = Ken.get('/en/new_order') # => <Resource id="/en/new_order" name="New Order">
16
41
 
17
42
  == REQUIREMENTS:
18
43
 
19
- * FIX (list of requirements)
44
+ - Ruby >=1.8.x
45
+ - RubyGems >=1.2.x
46
+ - Extlib >=0.9.x
20
47
 
21
48
  == INSTALL:
22
49
 
23
- * FIX (sudo gem install, anything else)
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.1'# Ken::VERSION
14
+ GEM_VERSION = '0.0.2'# Ken::VERSION
15
15
  GEM_DEPENDENCIES = [
16
16
  [ 'extlib', '>=0.9.10' ]
17
17
  # [ 'addressable', '~>2.0.1' ]
@@ -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
@@ -7,5 +7,10 @@ module Ken
7
7
  # def method_missing(name, *args, &blk)
8
8
  # @data.send name, *args, &blk
9
9
  # end
10
+
11
+ # add a linebreak after each entry
12
+ def to_s
13
+ self.inject("") { |m,i| "#{m}#{i.to_s}\n"}
14
+ end
10
15
  end
11
16
  end
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