html-schema 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +76 -0
- data/lib/html-schema.rb +83 -0
- data/lib/html-schema/api.rb +253 -0
- data/lib/html-schema/api/attribute.rb +54 -0
- data/lib/html-schema/api/object.rb +26 -0
- data/lib/html-schema/attribute.rb +43 -0
- data/lib/html-schema/configuration.rb +10 -0
- data/lib/html-schema/dsl.rb +23 -0
- data/lib/html-schema/helper.rb +10 -0
- data/lib/html-schema/microdata.rb +450 -0
- data/lib/html-schema/microdata/attribute.rb +9 -0
- data/lib/html-schema/microdata/object.rb +13 -0
- data/lib/html-schema/microformat.rb +218 -0
- data/lib/html-schema/microformat/attribute.rb +9 -0
- data/lib/html-schema/microformat/object.rb +9 -0
- data/lib/html-schema/object.rb +63 -0
- data/spec/schema_spec.rb +86 -0
- data/spec/spec_helper.rb +14 -0
- metadata +71 -0
data/Rakefile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require "rake/rdoctask"
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = "html-schema"
|
7
|
+
s.authors = ["Lance Pollard"]
|
8
|
+
s.version = "0.2.0"
|
9
|
+
s.description = "Unified Ruby API for HTML5 Microdata and Microformats"
|
10
|
+
s.summary = "Unified Ruby API for HTML5 Microdata and Microformats"
|
11
|
+
s.homepage = "http://github.com/viatropos/html-schema"
|
12
|
+
s.email = "lancejpollard@gmail.com"
|
13
|
+
s.rubyforge_project = "html-schema"
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.files = %w(Rakefile) + Dir["{lib,rails,spec}/**/*"] - Dir["spec/tmp"]
|
16
|
+
s.require_path = "lib"
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
20
|
+
pkg.gem_spec = spec
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'run unit tests'
|
24
|
+
task :test do
|
25
|
+
Dir["test/**/*"].each do |file|
|
26
|
+
next unless File.basename(file) =~ /test_/
|
27
|
+
next unless File.extname(file) == ".rb"
|
28
|
+
system "ruby #{file}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Create .gemspec file (useful for github)"
|
33
|
+
task :gemspec do
|
34
|
+
File.open("#{spec.name}.gemspec", "w") do |f|
|
35
|
+
f.puts spec.to_ruby
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Build the gem into the current directory"
|
40
|
+
task :gem => :gemspec do
|
41
|
+
`gem build #{spec.name}.gemspec`
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Publish gem to rubygems"
|
45
|
+
task :publish => [:package] do
|
46
|
+
%x[gem push #{spec.name}-#{spec.version}.gem]
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Print a list of the files to be put into the gem"
|
50
|
+
task :manifest do
|
51
|
+
File.open("Manifest", "w") do |f|
|
52
|
+
spec.files.each do |file|
|
53
|
+
f.puts file
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Install the gem locally"
|
59
|
+
task :install => [:package] do
|
60
|
+
File.mkdir("pkg") unless File.exists?("pkg")
|
61
|
+
command = "gem install pkg/#{spec.name}-#{spec.version} --no-ri --no-rdoc"
|
62
|
+
command = "sudo #{command}" if ENV["SUDO"] == true
|
63
|
+
sh %{#{command}}
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "Generate the rdoc"
|
67
|
+
Rake::RDocTask.new do |rdoc|
|
68
|
+
files = ["README.md", "lib/**/*.rb"]
|
69
|
+
rdoc.rdoc_files.add(files)
|
70
|
+
rdoc.main = "README.md"
|
71
|
+
rdoc.title = spec.summary
|
72
|
+
end
|
73
|
+
|
74
|
+
task :yank do
|
75
|
+
`gem yank #{spec.name} -v #{spec.version}`
|
76
|
+
end
|
data/lib/html-schema.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
$:.unshift File.dirname(File.expand_path(__FILE__)) + "/html-schema"
|
4
|
+
|
5
|
+
class HTMLSchema
|
6
|
+
class << self
|
7
|
+
def root
|
8
|
+
@root ||= File.dirname(File.expand_path(__FILE__))
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure(&block)
|
12
|
+
yield configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
def configuration
|
16
|
+
@configuration ||= HTMLSchema::Configuration.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
api[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def instance
|
24
|
+
@instance ||= new
|
25
|
+
end
|
26
|
+
|
27
|
+
def instance=(value)
|
28
|
+
@instance = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def bootstrap!(format)
|
32
|
+
format_name = format == :api ? "API" : format.to_s.camelize
|
33
|
+
Dir["#{HTMLSchema.root}/html-schema/#{format}/**/*.rb"].inject({}) do |hash, file|
|
34
|
+
name = ::File.basename(file, File.extname(file))
|
35
|
+
hash[name.to_sym] = "::HTMLSchema::#{format_name}::#{name.camelize}".constantize.new if name !~ /^(base|feed|attribute)$/
|
36
|
+
hash
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(types = {})
|
42
|
+
self.class.instance = self
|
43
|
+
api.types.keys.each { |key| define_api_method(key) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def api
|
47
|
+
@api ||= HTMLSchema::API
|
48
|
+
end
|
49
|
+
|
50
|
+
def microdata
|
51
|
+
@microdata ||= HTMLSchema::Microdata
|
52
|
+
end
|
53
|
+
|
54
|
+
def microformat
|
55
|
+
@microformat ||= HTMLSchema::Microformat
|
56
|
+
end
|
57
|
+
|
58
|
+
# todo, iterate through tree, so you can visualize it however you want.
|
59
|
+
def each(&block)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def define_api_method(name)
|
65
|
+
self.class.send :define_method, name do
|
66
|
+
self.api[name]
|
67
|
+
end unless self.respond_to?(name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
require 'object'
|
72
|
+
require 'attribute'
|
73
|
+
require 'configuration'
|
74
|
+
require 'dsl'
|
75
|
+
require 'api/object'
|
76
|
+
require 'api/attribute'
|
77
|
+
require 'microdata/object'
|
78
|
+
require 'microdata/attribute'
|
79
|
+
require 'microformat/object'
|
80
|
+
require 'microformat/attribute'
|
81
|
+
require 'api'
|
82
|
+
require 'microdata'
|
83
|
+
require 'microformat'
|
@@ -0,0 +1,253 @@
|
|
1
|
+
class HTMLSchema
|
2
|
+
class API
|
3
|
+
extend HTMLSchema::DSL
|
4
|
+
|
5
|
+
type :object do
|
6
|
+
attribute :id
|
7
|
+
attribute :title
|
8
|
+
attribute :name
|
9
|
+
attribute :url
|
10
|
+
attribute :description
|
11
|
+
attribute :image
|
12
|
+
|
13
|
+
type :address do
|
14
|
+
attribute :street
|
15
|
+
attribute :suite
|
16
|
+
attribute :city
|
17
|
+
attribute :state
|
18
|
+
attribute :country
|
19
|
+
attribute :postal_code
|
20
|
+
attribute :post_office_box
|
21
|
+
end
|
22
|
+
|
23
|
+
type :composition do
|
24
|
+
attribute :abstract, :type => [:person, :organization]
|
25
|
+
attribute :average_rating, :type => :rating
|
26
|
+
attribute :award
|
27
|
+
attribute :rating, :type => :rating
|
28
|
+
attribute :genre
|
29
|
+
attribute :headline
|
30
|
+
attribute :language
|
31
|
+
attribute :interaction_count
|
32
|
+
attribute :family_friendly, :type => :boolean
|
33
|
+
attribute :keyword
|
34
|
+
attribute :offer, :type => :offer
|
35
|
+
attribute :review, :type => :review
|
36
|
+
attribute :editor, :type => :person
|
37
|
+
attribute :author, :type => :person
|
38
|
+
attribute :organization, :type => :organization
|
39
|
+
attribute :publisher, :type => :organization
|
40
|
+
attribute :location, :type => :address
|
41
|
+
attribute :videa, :type => :media
|
42
|
+
attribute :encoding, :type => :media
|
43
|
+
attribute :audio, :type => :media
|
44
|
+
attribute :tag
|
45
|
+
attribute :published_at, :type => :date
|
46
|
+
|
47
|
+
type :article do
|
48
|
+
attribute :body
|
49
|
+
attribute :section
|
50
|
+
end
|
51
|
+
|
52
|
+
type :media do
|
53
|
+
attribute :bitrate
|
54
|
+
attribute :size
|
55
|
+
attribute :url
|
56
|
+
attribute :embed_url
|
57
|
+
attribute :composition, :type => :article
|
58
|
+
attribute :format
|
59
|
+
attribute :player
|
60
|
+
attribute :allowed_in, :type => :address
|
61
|
+
attribute :subscription_required, :type => :boolean
|
62
|
+
attribute :expires_at, :type => :date
|
63
|
+
attribute :uploaded_at, :type => :date
|
64
|
+
attribute :duration, :as => :measurement
|
65
|
+
attribute :height, :type => :measurement
|
66
|
+
attribute :width, :type => :measurement
|
67
|
+
|
68
|
+
type :audio
|
69
|
+
type :image
|
70
|
+
type :video
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
type :coordinates do
|
75
|
+
attribute :elevation, :type => :measurement
|
76
|
+
attribute :latitude
|
77
|
+
attribute :longitude
|
78
|
+
end
|
79
|
+
|
80
|
+
type :event do
|
81
|
+
attribute :child_event, :type => :event
|
82
|
+
attribute :parent_event, :type => :event
|
83
|
+
attribute :start_date, :type => :date
|
84
|
+
attribute :end_date, :type => :date
|
85
|
+
attribute :location, :type => :address
|
86
|
+
attribute :duration, :type => :measurement
|
87
|
+
attribute :offer, :type => :offer
|
88
|
+
attribute :attendee, :type => :person
|
89
|
+
attribute :performer, :type => :person
|
90
|
+
attribute :organization, :type => :organization
|
91
|
+
end
|
92
|
+
|
93
|
+
type :figure do
|
94
|
+
attribute :image
|
95
|
+
attribute :legend
|
96
|
+
attribute :author, :type => [:person, :organization]
|
97
|
+
attribute :subject
|
98
|
+
end
|
99
|
+
|
100
|
+
type :item do
|
101
|
+
attribute :type
|
102
|
+
attribute :value
|
103
|
+
end
|
104
|
+
|
105
|
+
type :measurement do
|
106
|
+
attribute :value
|
107
|
+
attribute :unit
|
108
|
+
attribute :item, :type => [:text, :person, :organization, :media, :event]
|
109
|
+
end
|
110
|
+
|
111
|
+
type :offer do
|
112
|
+
attribute :rating, :type => :rating
|
113
|
+
attribute :availability
|
114
|
+
attribute :condition
|
115
|
+
attribute :item, :type => :product
|
116
|
+
attribute :price, :type => :measurement
|
117
|
+
attribute :min_price, :type => :measurement
|
118
|
+
attribute :max_price, :type => :measurement
|
119
|
+
attribute :currency
|
120
|
+
attribute :valid_until_date, :type => :date
|
121
|
+
attribute :review, :type => :review
|
122
|
+
attribute :seller, :type => :organization
|
123
|
+
attribute :count
|
124
|
+
end
|
125
|
+
|
126
|
+
type :organization do
|
127
|
+
attribute :address, :type => :address
|
128
|
+
attribute :average_rating, :type => :rating
|
129
|
+
attribute :contact, :type => [:person, :organization]
|
130
|
+
attribute :email
|
131
|
+
attribute :employee, :type => :person
|
132
|
+
attribute :event, :type => :event
|
133
|
+
attribute :fax
|
134
|
+
attribute :founder, :type => :person
|
135
|
+
attribute :founded_at, :type => :date
|
136
|
+
|
137
|
+
type :vendor do
|
138
|
+
attribute :branch_of, :type => :organization
|
139
|
+
attribute :hours
|
140
|
+
attribute :currency
|
141
|
+
attribute :payment_method
|
142
|
+
attribute :price_range
|
143
|
+
attribute :menu
|
144
|
+
attribute :reservations
|
145
|
+
attribute :cuisine
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
type :person do
|
150
|
+
attribute :address, :type => :address
|
151
|
+
attribute :home_address, :type => :address
|
152
|
+
attribute :work_address, :type => :address
|
153
|
+
|
154
|
+
# organizations
|
155
|
+
attribute :organization, :type => :organization
|
156
|
+
attribute :education, :type => :organization
|
157
|
+
attribute :membership, :type => :organization
|
158
|
+
attribute :company, :type => :organization
|
159
|
+
|
160
|
+
# events
|
161
|
+
attribute :performer_in, :type => :event
|
162
|
+
|
163
|
+
# dates
|
164
|
+
attribute :born_at, :type => :date
|
165
|
+
attribute :died_at, :type => :date
|
166
|
+
|
167
|
+
# relationships
|
168
|
+
attribute :children, :type => :person
|
169
|
+
attribute :parents, :type => :person
|
170
|
+
attribute :siblings, :type => :person
|
171
|
+
attribute :spouse, :type => :person
|
172
|
+
attribute :relationship, :type => :person
|
173
|
+
attribute :colleagues, :type => :person
|
174
|
+
# unidirectional
|
175
|
+
attribute :follows, :type => :person
|
176
|
+
# bidirectional
|
177
|
+
attribute :knows, :type => :person
|
178
|
+
|
179
|
+
# info
|
180
|
+
attribute :contact_info, :type => :contact
|
181
|
+
attribute :email
|
182
|
+
attribute :phone
|
183
|
+
attribute :fax
|
184
|
+
attribute :gender
|
185
|
+
attribute :interaction_count
|
186
|
+
attribute :job_title
|
187
|
+
attribute :nationality, :type => :place
|
188
|
+
|
189
|
+
type :author
|
190
|
+
type :acquaintance
|
191
|
+
type :child
|
192
|
+
type :colleague
|
193
|
+
type :contact
|
194
|
+
type :roommate
|
195
|
+
type :coworker
|
196
|
+
type :crush
|
197
|
+
type :date
|
198
|
+
type :editor
|
199
|
+
type :fan
|
200
|
+
type :friend
|
201
|
+
type :kin
|
202
|
+
type :me
|
203
|
+
type :met
|
204
|
+
type :muse
|
205
|
+
type :neighbor
|
206
|
+
type :sibling
|
207
|
+
type :spouse
|
208
|
+
type :sweetheart
|
209
|
+
type :member
|
210
|
+
type :sponsor
|
211
|
+
type :user
|
212
|
+
end
|
213
|
+
|
214
|
+
type :place do
|
215
|
+
attribute :address, :type => :address
|
216
|
+
attribute :rating, :type => :rating
|
217
|
+
attribute :surrounding, :type => :place
|
218
|
+
attribute :event, :type => :event
|
219
|
+
attribute :fax
|
220
|
+
attribute :coordinates, :type => :coordinates
|
221
|
+
attribute :interaction_count
|
222
|
+
attribute :map
|
223
|
+
attribute :image, :type => :media
|
224
|
+
attribute :review, :type => :review
|
225
|
+
attribute :phone
|
226
|
+
end
|
227
|
+
|
228
|
+
type :product do
|
229
|
+
attribute :rating, :type => :rating
|
230
|
+
attribute :brand, :type => :organization
|
231
|
+
attribute :manufacturer, :type => :organization
|
232
|
+
attribute :model
|
233
|
+
attribute :offer, :type => :offer
|
234
|
+
attribute :review, :type => :review
|
235
|
+
end
|
236
|
+
|
237
|
+
type :rating do
|
238
|
+
attribute :best
|
239
|
+
attribute :value
|
240
|
+
attribute :worst
|
241
|
+
attribute :item, :type => [:person, :event, :media, :place, :organization]
|
242
|
+
attribute :rating_count
|
243
|
+
attribute :review_count
|
244
|
+
end
|
245
|
+
|
246
|
+
type :review do
|
247
|
+
attribute :body
|
248
|
+
attribute :item, :type => [:person, :event, :media, :place, :organization]
|
249
|
+
attribute :rating, :type => :rating
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class HTMLSchema
|
2
|
+
class API
|
3
|
+
class Attribute < HTMLSchema::Attribute
|
4
|
+
def microdata
|
5
|
+
if @microdata.nil?
|
6
|
+
object = HTMLSchema.instance.microdata[parent]
|
7
|
+
object = object[_name] if object
|
8
|
+
object = false if object.blank?
|
9
|
+
@microdata = object
|
10
|
+
end
|
11
|
+
|
12
|
+
@microdata
|
13
|
+
end
|
14
|
+
|
15
|
+
def microdata?
|
16
|
+
!!microdata
|
17
|
+
end
|
18
|
+
|
19
|
+
def microformat
|
20
|
+
if @microformat.nil?
|
21
|
+
object = HTMLSchema.instance.microformat[parent]
|
22
|
+
object = object[_name] if object
|
23
|
+
object = false if object.blank?
|
24
|
+
@microformat = object
|
25
|
+
end
|
26
|
+
@microformat
|
27
|
+
end
|
28
|
+
|
29
|
+
def microformat?
|
30
|
+
!!microformat
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_microdata
|
34
|
+
microdata.to_hash
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_microformat
|
38
|
+
microformat.to_hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_hash
|
42
|
+
if microdata? && microformat?
|
43
|
+
to_microdata.merge(to_microformat)
|
44
|
+
elsif microdata?
|
45
|
+
to_microdata
|
46
|
+
elsif microformat?
|
47
|
+
to_microformat
|
48
|
+
else
|
49
|
+
{}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|