howkast 0.0.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.
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ class String
4
+ def modulize
5
+ gsub('__','/').
6
+ gsub(/\/(.?)/u){ "::#{$1.upcase}" }.
7
+ gsub(/(?:_+|-+)([a-z])/u){ $1.upcase }.
8
+ gsub(/(\A|\s)([a-z])/u){ $1 + $2.upcase }
9
+ end
10
+
11
+ def parse
12
+ rfc2822 = "(#{Time::RFC2822_DAY_NAME.join('|')}, )? \d{1,2} #{Time::RFC2822_MONTH_NAME.join('|')} \d{4,4} \d{2,2}:\d{2,2}:\d{2,2} [+-]\d{4,4}"
13
+ ansi = "#{Time::RFC2822_DAY_NAME.join('|')} #{Time::RFC2822_MONTH_NAME.join('|')} +\d{1,2} \d{2,2}:\d{2,2}:\d{2,2} [A-Z]{3,3} \d{4,4}"
14
+ case self
15
+ when /^[+-]?\d+$/u
16
+ to_i
17
+ when /^[+-]?\d+\.\d+/u
18
+ to_f
19
+ when /^(true|false)$/iu
20
+ self =~ /^true$/iu ? true : false
21
+ when /^#{rfc2822}|#{ansi}$/u
22
+ Time.parse(self) rescue self
23
+ else
24
+ self
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ class Howkast::Model
4
+ def self.synthesize name, data
5
+ classname = name.modulize
6
+ attrdef = Proc.new{ data.keys.each{ |field| attr_reader field } }
7
+ if const_defined? classname
8
+ klass = const_get classname
9
+ klass.class_eval &attrdef
10
+ klass
11
+ else
12
+ const_set classname, Class.new(self, &attrdef)
13
+ end
14
+ end
15
+
16
+ def initialize processor, data, &block
17
+ data.each do |field, value|
18
+ value = if block and value.respond_to? :each
19
+ block[field, value]
20
+ elsif value.nil?
21
+ processor.default_for field
22
+ else
23
+ value
24
+ end
25
+ instance_variable_set :"@#{field}", self.class.parse(value)
26
+ end
27
+ end
28
+
29
+ def instance_attributes
30
+ instance_variables.map{ |name| "#{name}"[1 .. -1].to_sym }
31
+ end
32
+
33
+ def self.parse value
34
+ value.instance_of?(String) ? value.parse : value
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ module Howkast::Processor
4
+ class Base
5
+ class << self
6
+ # The name of the processor dictates the path used to communicate to the
7
+ # API server. override to provide an alternate path.
8
+ def path
9
+ "#{self}".split('::').last.downcase unless "#{self}" =~ /::Base$/u
10
+ end
11
+
12
+ # Override to provide a value for field when field is nil.
13
+ def default_for field; end
14
+
15
+ # Override to massage args and options as needed.
16
+ def filter args, options; end
17
+
18
+ # Override to process data and restructure the returned value (eg: parse
19
+ # data and return a Howkast::Model::Video instance). By default it
20
+ # simply returns data in its 'raw' form (the Hash from HTTParty's parsed
21
+ # response)
22
+ def parse_element data
23
+ data
24
+ end
25
+
26
+ private
27
+ # Process an entry (identified by key) in data and return an Array of
28
+ # model. It assumes that data[key] represents a list of like data.
29
+ def parse_list key, data, model = nil, &block
30
+ list = (data || { })[key]
31
+ list = [list] if list.instance_of? Hash
32
+ list.map do |data|
33
+ name = (model || key)
34
+ klass = Howkast::Model.synthesize(name, data)
35
+ klass.new self, data, &block
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Category
4
+ # - id
5
+ # - name
6
+ # - parent_id
7
+ # - permalink
8
+ # - parents*
9
+ # - subcategories*
10
+ #
11
+ module Howkast::Processor
12
+ class Categories < Base
13
+ class << self
14
+ def filter args, options
15
+ args << options.delete(:id)
16
+ args.compact!
17
+ options = { }
18
+ end
19
+
20
+ def parse_element data
21
+ expander = ->(key, value){ expand key, value }
22
+ if data.has_key? 'category'
23
+ data = data['category']
24
+ klass = Howkast::Model.synthesize('Category', data)
25
+ klass.new self, data, &expander
26
+ else
27
+ parse_list 'category', data['categories'], &expander
28
+ end
29
+ end
30
+
31
+ def default_for field
32
+ [] if %w{ parents categories subcategories }.include? field
33
+ end
34
+
35
+ private
36
+ def expand key, value
37
+ case key
38
+ when 'parents'
39
+ value['category'] = [value['category']] \
40
+ unless value['category'].instance_of? Array
41
+ parse_element 'categories' => value
42
+ when 'subcategories'
43
+ parse_element 'categories' => value
44
+ else
45
+ value
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Playlist
4
+ # - created_at
5
+ # - description
6
+ # - id
7
+ # - permalink
8
+ # - playlist_thumbnail_url
9
+ # - rating
10
+ # - thumbnail_url
11
+ # - title
12
+ # - version
13
+ # - videos*
14
+ # - videos_count
15
+ # - views
16
+ #
17
+ module Howkast::Processor
18
+ class Playlists < Base
19
+ class << self
20
+ def filter args, options
21
+ args << options.delete(:id)
22
+ args.compact!
23
+ options = { }
24
+ end
25
+
26
+ def parse_element data
27
+ expander = ->(key, value){ expand key, value }
28
+ if data.has_key? 'playlists'
29
+ parse_list 'playlist', data['playlists'], &expander
30
+ else
31
+ klass = Howkast::Model.synthesize('Playlist', data)
32
+ klass.new self, data, &expander
33
+ end
34
+ end
35
+
36
+ def default_for field
37
+ [] if %w{ playlists videos }.include? field
38
+ end
39
+
40
+ private
41
+ def expand key, value
42
+ case key
43
+ when 'playlists'
44
+ Playlists.parse_element 'playlists' => value
45
+ when 'videos'
46
+ Videos.parse_element 'videos' => value
47
+ else
48
+ value
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Search
4
+ # - title
5
+ # - videos*
6
+ # - version
7
+ #
8
+ module Howkast::Processor
9
+ class Search < Base
10
+ class << self
11
+ def filter args, options
12
+ options[:q] = options.delete(:query)
13
+ # HACK: The Howcast API service responds with HTTP500 error if the
14
+ # :q parameter on search is an empty string - so we plug it with
15
+ # something that *might not* exist and hopefully it will return an
16
+ # empty list :-)
17
+ options[:q] = '6c6d1613339399efd0bc74fe12b14dd3' if options[:q].empty?
18
+ end
19
+
20
+ def parse_element data
21
+ expander = ->(key, value){ expand key, value }
22
+ klass = Howkast::Model.synthesize('Search', data)
23
+ klass.new self, data, &expander
24
+ end
25
+
26
+ def default_for field
27
+ [] if %w{ videos }.include? field
28
+ end
29
+
30
+ private
31
+ def expand key, value
32
+ case key
33
+ when 'videos'
34
+ Videos.parse_element 'videos' => value
35
+ else
36
+ value
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ #
3
+ # title
4
+ # login
5
+ # count
6
+ # views
7
+ # firstname
8
+ # lastname
9
+ # thumbnail_url
10
+ # videos
11
+ # version
12
+ #
13
+ #created_at
14
+ #description
15
+ #id
16
+ #permalink
17
+ #rating
18
+ #thumbnail_url
19
+ #title
20
+ #videos_count
21
+ #views
22
+ #
23
+ module Howkast::Processor
24
+ class Users < Base
25
+ class << self
26
+ def filter args, options
27
+ args << options.delete(:id)
28
+ args << :profile
29
+ args << Array(options.delete(:resource))
30
+ args.compact!
31
+ end
32
+
33
+ def parse_element data
34
+ expander = ->(key, value){ expand key, value }
35
+ if data.has_key? 'records'
36
+ data['playlists'] = nil
37
+ data.delete 'records'
38
+ end
39
+ klass = Howkast::Model.synthesize('User', data)
40
+ klass.new self, data, &expander
41
+ end
42
+
43
+ def default_for field
44
+ [] if %w{ playlists videos }.include? field
45
+ end
46
+
47
+ private
48
+ def expand key, value
49
+ case key
50
+ when 'playlists', 'records'
51
+ Playlists.parse_element 'playlists' => value
52
+ when 'videos'
53
+ Videos.parse_element 'videos' => value
54
+ else
55
+ value
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Video
4
+ # - badges
5
+ # - category_hierarchy*
6
+ # - category_id
7
+ # - comment_count
8
+ # - comments*
9
+ # - content_rating
10
+ # - created_at
11
+ # - description
12
+ # - duration
13
+ # - easy_steps
14
+ # - edit_url
15
+ # - embed
16
+ # - filename
17
+ # - filename
18
+ # - height
19
+ # - id
20
+ # - ingredients*
21
+ # - markers*
22
+ # - overlay*
23
+ # - permalink
24
+ # - rating
25
+ # - related_videos*
26
+ # - state
27
+ # - tags
28
+ # - thumbnail_url
29
+ # - title
30
+ # - type
31
+ # - username
32
+ # - views
33
+ # - width
34
+ #
35
+ # Marker
36
+ # - id
37
+ # - position
38
+ # - timemarker
39
+ # - type
40
+ # - thumbnail_url
41
+ # - title
42
+ # - textile_text
43
+ # - text
44
+ #
45
+ module Howkast::Processor
46
+ class Videos < Base
47
+ class << self
48
+ def filter args, options
49
+ args << options.delete(:id)
50
+ args << options.delete(:sort)
51
+ args << options.delete(:filter)
52
+ args << options.delete(:category)
53
+ args << options.delete(:page)
54
+ args.compact!
55
+ end
56
+
57
+ def parse_element data
58
+ expander = ->(key, value){ expand key, value }
59
+ if data.has_key? 'video'
60
+ data = data['video']
61
+ klass = Howkast::Model.synthesize('Video', data)
62
+ klass.new self, data, &expander
63
+ else
64
+ parse_list 'video', data['videos'], &expander
65
+ end
66
+ end
67
+
68
+ def default_for field
69
+ [] if %w{ category_hierarchy ingredients markers related_videos }.include? field
70
+ end
71
+
72
+ private
73
+ def expand key, value
74
+ case key
75
+ when 'category_hierarchy'
76
+ value['category'] = case value['category']
77
+ when Array, String
78
+ Array(value['category']).map{ |category| { 'name' => category } }
79
+ when Hash
80
+ value['category']
81
+ end
82
+ Categories.parse_element 'categories' => value
83
+ when 'comments'
84
+ value['count']
85
+ when 'ingredients'
86
+ value['ingredient']
87
+ when 'markers'
88
+ parse_list 'marker', value
89
+ when 'related_videos'
90
+ parse_element 'videos' => value
91
+ when 'overlay'
92
+ klass = Howkast::Model.synthesize('Overlay', value)
93
+ klass.new self, value
94
+ else
95
+ value
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'yaml'
3
+ begin
4
+ require 'howkast'
5
+ rescue LoadError
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ require 'howkast'
8
+ end
9
+
10
+ Howkast::configure YAML.load File.read('.howkast')
11
+ howcast = Howkast::API.new
12
+ video = howcast.video :id => 3907
13
+ puts video.category_hierarchy.first.name
14
+
15
+ video = howcast.video :id => 5072
16
+ puts video.category_hierarchy
17
+ puts video.category_hierarchy.first.name
18
+
19
+ #search = howcast.search :query => 'jujitus'
20
+ #puts search.videos.count
21
+ #
22
+ #search = howcast.search :query => 'jujitsu'
23
+ #puts search.videos.count
24
+ #
25
+ #search = howcast.search :query => ''
26
+ #puts search.videos.count
27
+ #search.videos.each do |video|
28
+ # puts video.title
29
+ #end