feedparser 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +36 -7
- data/README.md +145 -10
- data/Rakefile +1 -1
- data/lib/feedparser.rb +3 -0
- data/lib/feedparser/author.rb +39 -0
- data/lib/feedparser/builder/atom.rb +64 -17
- data/lib/feedparser/builder/json.rb +46 -10
- data/lib/feedparser/builder/rss.rb +94 -15
- data/lib/feedparser/feed.rb +30 -6
- data/lib/feedparser/generator.rb +34 -0
- data/lib/feedparser/item.rb +31 -6
- data/lib/feedparser/tag.rb +23 -0
- data/lib/feedparser/version.rb +2 -2
- data/test/feeds/books/nostarch.rss +125 -0
- data/test/feeds/books/oreilly.feedburner.atom +387 -0
- data/test/feeds/books/pragprog.rss +148 -0
- data/test/feeds/byparker.json +4 -4
- data/test/feeds/daringfireball.atom +8 -1
- data/test/feeds/daringfireball.json +28 -0
- data/test/feeds/googlegroups.atom +2 -2
- data/test/feeds/googlegroups2.atom +1 -1
- data/test/feeds/headius.atom +6 -5
- data/test/feeds/inessential.json +13 -4
- data/test/feeds/jsonfeed.json +8 -3
- data/test/feeds/{lambdatheultimate.rss2 → lambdatheultimate.rss} +0 -0
- data/test/feeds/{learnenough.atom → learnenough.feedburner.atom} +12 -9
- data/test/feeds/news/nytimes-blogs-bits.rss +333 -0
- data/test/feeds/news/nytimes-paul-krugman.rss +60 -0
- data/test/feeds/news/nytimes-tech.rss +653 -0
- data/test/feeds/news/nytimes-thomas-l-friedman.rss +80 -0
- data/test/feeds/news/nytimes.rss +607 -0
- data/test/feeds/news/washingtonpost-blogs-innovations.rss +183 -0
- data/test/feeds/news/washingtonpost-politics.rss +35 -0
- data/test/feeds/news/washingtonpost-world.rss +29 -0
- data/test/feeds/ongoing.atom +1619 -0
- data/test/feeds/osm/blog.openstreetmap.rss +252 -0
- data/test/feeds/osm/blogs.openstreetmap.rss +585 -0
- data/test/feeds/osm/mapbox.rss +1883 -0
- data/test/feeds/{railstutorial.atom → railstutorial.feedburner.atom} +28 -27
- data/test/feeds/{rubyflow.rss2 → rubyflow.feedburner.rss} +7 -3
- data/test/feeds/{rubymine.rss2 → rubymine.feedburner.rss} +5 -6
- data/test/feeds/scripting.rss +881 -0
- data/test/feeds/{sitepoint.rss2 → sitepoint.rss} +8 -9
- data/test/feeds/spec/atom/author.atom +48 -0
- data/test/feeds/spec/atom/authors.atom +70 -0
- data/test/feeds/spec/atom/categories.atom +66 -0
- data/test/feeds/spec/json/microblog.json +11 -2
- data/test/feeds/spec/json/tags.json +33 -0
- data/test/feeds/spec/rss/author.rss +41 -0
- data/test/feeds/spec/rss/categories.rss +64 -0
- data/test/feeds/spec/rss/creator.rss +38 -0
- data/test/feeds/{xkcd.rss2 → xkcd.rss} +0 -0
- data/test/helper.rb +21 -16
- data/test/test_atom.rb +1 -1
- data/test/test_atom_live.rb +1 -1
- data/test/test_authors.rb +26 -0
- data/test/test_books.rb +25 -0
- data/test/test_feeds.rb +4 -2
- data/test/test_rss.rb +4 -4
- data/test/test_tags.rb +25 -0
- metadata +39 -10
@@ -32,34 +32,50 @@ class JsonFeedBuilder
|
|
32
32
|
feed.summary = h['description']
|
33
33
|
|
34
34
|
|
35
|
+
if h['author']
|
36
|
+
feed.authors << build_author( h['author'] )
|
37
|
+
end
|
38
|
+
|
35
39
|
|
36
|
-
items = []
|
37
40
|
h['items'].each do |hash_item|
|
38
|
-
items <<
|
41
|
+
feed.items << build_item( hash_item )
|
39
42
|
end
|
40
|
-
feed.items = items
|
41
43
|
|
42
44
|
feed # return new feed
|
43
45
|
end # method build_feed_from_json
|
44
46
|
|
45
47
|
|
48
|
+
def build_author( h )
|
49
|
+
author = Author.new
|
50
|
+
|
51
|
+
author.name = h['name']
|
52
|
+
author.url = h['url']
|
53
|
+
author.avatar = h['avatar']
|
54
|
+
|
55
|
+
author
|
56
|
+
end
|
57
|
+
|
46
58
|
|
47
|
-
|
59
|
+
|
60
|
+
def build_item( h )
|
48
61
|
item = Item.new # Item.new
|
49
62
|
|
50
|
-
item.guid
|
51
|
-
item.title
|
52
|
-
item.url
|
63
|
+
item.guid = h['id']
|
64
|
+
item.title = h['title']
|
65
|
+
item.url = h['url']
|
66
|
+
item.external_url = h['external_url']
|
53
67
|
|
54
68
|
## convert date if present (from string to date type)
|
55
69
|
date_published_str = h['date_published']
|
56
70
|
if date_published_str
|
57
|
-
item.
|
71
|
+
item.published_local = DateTime.iso8601( date_published_str )
|
72
|
+
item.published = item.published_local.utc
|
58
73
|
end
|
59
74
|
|
60
75
|
date_modified_str = h['date_modified']
|
61
76
|
if date_modified_str
|
62
|
-
item.
|
77
|
+
item.updated_local = DateTime.iso8601( date_modified_str )
|
78
|
+
item.updated = item.updated_local.utc
|
63
79
|
end
|
64
80
|
|
65
81
|
|
@@ -67,8 +83,28 @@ class JsonFeedBuilder
|
|
67
83
|
item.content_text = h['content_text']
|
68
84
|
item.summary = h['summary']
|
69
85
|
|
86
|
+
if h['author']
|
87
|
+
item.authors << build_author( h['author'] )
|
88
|
+
end
|
89
|
+
|
90
|
+
if h['tags']
|
91
|
+
h['tags'].each do |json_tag|
|
92
|
+
item.tags << build_tag( json_tag )
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
70
96
|
item
|
71
|
-
end # method
|
97
|
+
end # method build_item
|
98
|
+
|
99
|
+
|
100
|
+
def build_tag( json_tag )
|
101
|
+
## pp rss_cat
|
102
|
+
tag = Tag.new
|
103
|
+
|
104
|
+
tag.name = json_tag
|
105
|
+
|
106
|
+
tag
|
107
|
+
end # build_tag
|
72
108
|
|
73
109
|
|
74
110
|
end # JsonFeedBuilder
|
@@ -35,25 +35,85 @@ class RssFeedBuilder
|
|
35
35
|
feed.summary = handle_content( rss_feed.channel.description, 'feed.description => summary' ) # required
|
36
36
|
feed.url = rss_feed.channel.link # required
|
37
37
|
|
38
|
-
feed.
|
39
|
-
feed.
|
38
|
+
feed.updated_local = handle_date( rss_feed.channel.lastBuildDate, 'feed.lastBuildDate => updated' ) # optional
|
39
|
+
feed.updated = feed.updated_local.utc if feed.updated_local
|
40
40
|
|
41
|
-
|
42
|
-
feed.
|
41
|
+
feed.published_local = handle_date( rss_feed.channel.pubDate, 'feed.pubDate => published' ) # optional
|
42
|
+
feed.published = feed.published_local.utc if feed.published_local
|
43
43
|
|
44
44
|
logger.debug " rss | feed.generator >#{rss_feed.channel.generator}< : #{rss_feed.channel.generator.class.name}"
|
45
45
|
|
46
|
+
feed.generator.text = rss_feed.channel.generator # optional
|
47
|
+
feed.generator.name = feed.generator.text ## note: for now set also name/title to "unparsed" (content) line (may change in the future!!!)
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
## check for managingEditor and/or webMaster
|
52
|
+
|
53
|
+
if rss_feed.channel.managingEditor
|
54
|
+
author = Author.new
|
55
|
+
author.text = rss_feed.channel.managingEditor.strip
|
56
|
+
author.name = author.text ## note: for now use "unparsed" (content) line also for name
|
57
|
+
feed.authors << author
|
58
|
+
end
|
59
|
+
|
60
|
+
if rss_feed.channel.webMaster
|
61
|
+
author = Author.new
|
62
|
+
author.text = rss_feed.channel.webMaster.strip
|
63
|
+
author.name = author.text ## note: for now use "unparsed" (content) line also for name
|
64
|
+
feed.authors << author
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
## check for dublin core (dc) metadata
|
69
|
+
|
70
|
+
if rss_feed.channel.dc_creator
|
71
|
+
## note: dc_creator wipes out authors if set with rss tag(s)
|
72
|
+
authors = []
|
73
|
+
authors << build_author_from_dublic_core_creator( rss_feed.channel.dc_creator )
|
74
|
+
feed.authors = authors
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
### check for categories (tags)
|
79
|
+
|
80
|
+
rss_feed.channel.categories.each do |rss_cat|
|
81
|
+
feed.tags << build_tag( rss_cat )
|
82
|
+
end
|
83
|
+
|
46
84
|
|
47
|
-
items = []
|
48
85
|
rss_feed.items.each do |rss_item|
|
49
|
-
items <<
|
86
|
+
feed.items << build_item( rss_item )
|
50
87
|
end
|
51
|
-
feed.items = items
|
52
88
|
|
53
89
|
feed # return new feed
|
54
90
|
end
|
55
91
|
|
56
|
-
|
92
|
+
|
93
|
+
def build_author_from_dublic_core_creator( dc_creator )
|
94
|
+
author = Author.new
|
95
|
+
author.text = dc_creator.strip
|
96
|
+
author.name = author.text # note: for now use "unparsed" creator line also for name (may change in the future!!!)
|
97
|
+
author
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
def build_tag( rss_cat )
|
103
|
+
## pp rss_cat
|
104
|
+
tag = Tag.new
|
105
|
+
|
106
|
+
## note: always strip leading n trailing spaces
|
107
|
+
## and add if preset (not blank/empty e.g. not nil or "")
|
108
|
+
tag.name = rss_cat.content.strip if rss_cat.content
|
109
|
+
tag.domain = rss_cat.domain.strip if rss_cat.domain
|
110
|
+
|
111
|
+
tag
|
112
|
+
end # build_tag
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
def build_item( rss_item )
|
57
117
|
|
58
118
|
item = Item.new
|
59
119
|
|
@@ -79,7 +139,8 @@ class RssFeedBuilder
|
|
79
139
|
logger.debug " rss | item.content_encoded[0..40] >#{rss_item.content_encoded ? rss_item.content_encoded[0..40] : ''}< : #{rss_item.content_encoded.class.name}"
|
80
140
|
|
81
141
|
|
82
|
-
item.
|
142
|
+
item.updated_local = handle_date( rss_item.pubDate, 'item.pubDate => updated' )
|
143
|
+
item.updated = item.updated_local.utc if item.updated_local
|
83
144
|
|
84
145
|
|
85
146
|
## fix/todo: check if rss_item.guid present? !!!!
|
@@ -94,13 +155,31 @@ class RssFeedBuilder
|
|
94
155
|
logger.warn " rss | item.guid.content missing !!!! - using link for guid"
|
95
156
|
end
|
96
157
|
|
97
|
-
### todo: add support or authors (incl. dc:creator)
|
98
|
-
## <dc:creator>Dhaivat Pandya</dc:creator>
|
99
158
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
159
|
+
if rss_item.author
|
160
|
+
author = Author.new
|
161
|
+
author.text = rss_item.author.strip
|
162
|
+
author.name = author.text ## note: for now use "unparsed" (content) line also for name
|
163
|
+
item.authors << author
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
## check for dublin core (dc) metadata
|
168
|
+
|
169
|
+
if rss_item.dc_creator
|
170
|
+
## note: dc_creator wipes out authors if set with rss tag(s)
|
171
|
+
authors = []
|
172
|
+
authors << build_author_from_dublic_core_creator( rss_item.dc_creator )
|
173
|
+
item.authors = authors
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
### check for categories (tags)
|
178
|
+
|
179
|
+
rss_item.categories.each do |rss_cat|
|
180
|
+
item.tags << build_tag( rss_cat )
|
181
|
+
end
|
182
|
+
|
104
183
|
|
105
184
|
item
|
106
185
|
end # method build_feed_item_from_rss
|
data/lib/feedparser/feed.rb
CHANGED
@@ -4,14 +4,27 @@ module FeedParser
|
|
4
4
|
|
5
5
|
class Feed
|
6
6
|
|
7
|
-
attr_accessor :format # e.g. atom|rss 2.0|etc.
|
7
|
+
attr_accessor :format # e.g. atom|rss 2.0|json etc.
|
8
8
|
attr_accessor :title
|
9
9
|
attr_accessor :url ## todo - add alias site_url/home_page_url/page_url - why? why not??
|
10
|
-
attr_accessor :feed_url
|
10
|
+
attr_accessor :feed_url
|
11
11
|
|
12
12
|
|
13
13
|
attr_accessor :items
|
14
14
|
|
15
|
+
attr_accessor :authors
|
16
|
+
def authors?() @authors && @authors.size > 0; end
|
17
|
+
## note: author? is an alias for authors?
|
18
|
+
alias :author? :authors?
|
19
|
+
|
20
|
+
## add author shortcut e.g. equals authors[0] - for now only read only
|
21
|
+
## fix: also add author= why? why not???
|
22
|
+
def author() @authors[0]; end
|
23
|
+
|
24
|
+
|
25
|
+
attr_accessor :tags
|
26
|
+
def tags?() @tags && @tags.size > 0; end
|
27
|
+
|
15
28
|
|
16
29
|
def summary?() @summary.nil? == false; end
|
17
30
|
attr_accessor :summary # e.g. description (rss)|subtitle (atom)
|
@@ -26,24 +39,35 @@ class Feed
|
|
26
39
|
## for now alias summary to subtitle
|
27
40
|
alias :subtitle :summary
|
28
41
|
alias :subtitle= :summary=
|
42
|
+
alias :subtitle? :summary?
|
29
43
|
|
30
44
|
|
31
45
|
|
32
46
|
def updated?() @updated.nil? == false; end
|
33
|
-
attr_accessor :updated # e.g. lastBuildDate (rss)|updated (atom)
|
47
|
+
attr_accessor :updated # e.g. lastBuildDate (rss)|updated (atom) -- always (converted) to utc
|
48
|
+
attr_accessor :updated_local # "unparsed" local datetime as in feed (NOT converted to utc)
|
34
49
|
|
35
50
|
def published?() @published.nil? == false; end
|
36
|
-
attr_accessor :published
|
51
|
+
attr_accessor :published # e.g. pubDate (rss)\n/a (atom) -- note: published is basically an alias for created
|
52
|
+
attr_accessor :published_local # "unparsed" local datetime as in feed (NOT converted to utc)
|
37
53
|
|
38
54
|
|
39
55
|
attr_accessor :generator
|
40
|
-
attr_accessor :generator_version # e.g. @version (atom)
|
41
|
-
attr_accessor :generator_uri # e.g. @uri (atom) - use alias url/link ???
|
42
56
|
|
43
57
|
|
44
58
|
## fix:
|
45
59
|
# add pretty printer/inspect (exclude object)
|
46
60
|
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
## note: make items, authors, tags empty arrays on startup (e.g. not nil)
|
64
|
+
@items = []
|
65
|
+
@authors = []
|
66
|
+
@tags = []
|
67
|
+
|
68
|
+
@generator = Generator.new
|
69
|
+
end
|
70
|
+
|
47
71
|
end # class Feed
|
48
72
|
|
49
73
|
end # module FeedParser
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FeedParser
|
4
|
+
|
5
|
+
class Generator
|
6
|
+
|
7
|
+
attr_accessor :name
|
8
|
+
## note: title is an alias for name
|
9
|
+
alias :title :name
|
10
|
+
alias :title= :name=
|
11
|
+
|
12
|
+
attr_accessor :version
|
13
|
+
|
14
|
+
attr_accessor :url
|
15
|
+
## note: uri is an alias for url
|
16
|
+
alias :uri :url ## add atom alias for uri - why? why not?
|
17
|
+
alias :uri= :url=
|
18
|
+
|
19
|
+
|
20
|
+
attr_accessor :text # note: holds "unparsed" text (content) line form rss:generator
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
## note: to_s - allows to use just generator in templates
|
24
|
+
## will by default return name if present or as fallback "unparsed" text line
|
25
|
+
if @name ## not blank
|
26
|
+
@name
|
27
|
+
else
|
28
|
+
@text
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end # class Generator
|
33
|
+
|
34
|
+
end # module FeedParser
|
data/lib/feedparser/item.rb
CHANGED
@@ -6,6 +6,11 @@ class Item
|
|
6
6
|
|
7
7
|
attr_accessor :title
|
8
8
|
attr_accessor :url
|
9
|
+
attr_accessor :external_url
|
10
|
+
|
11
|
+
# note: related_url is an alias for external_url
|
12
|
+
alias :related_url :external_url ## link rel=related used in atom
|
13
|
+
alias :related_url= :external_url=
|
9
14
|
|
10
15
|
|
11
16
|
## note: only content/content_html should use html;
|
@@ -33,20 +38,40 @@ class Item
|
|
33
38
|
|
34
39
|
def updated?() @updated.nil? == false; end
|
35
40
|
attr_accessor :updated # pubDate (RSS)|updated (Atom)
|
41
|
+
attr_accessor :updated_local # "unparsed" local datetime as in feed (NOT converted to utc)
|
36
42
|
|
37
43
|
def published?() @published.nil? == false; end
|
38
44
|
attr_accessor :published # note: published is basically an alias for created
|
45
|
+
attr_accessor :published_local # "unparsed" local datetime as in feed (NOT converted to utc)
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
attr_accessor :id
|
50
|
+
|
51
|
+
## note: guid is an alias for id
|
52
|
+
alias :guid :id
|
53
|
+
alias :guid= :id=
|
39
54
|
|
55
|
+
attr_accessor :authors
|
56
|
+
## add author shortcut e.g. equals authors[0] - for now only read only
|
57
|
+
## fix: also add author= why? why not???
|
58
|
+
def authors?() @authors && @authors.size > 0; end
|
59
|
+
## note: author? is an alias for authors?
|
60
|
+
alias :author? :authors?
|
40
61
|
|
41
|
-
|
62
|
+
## add author shortcut e.g. equals authors[0] - for now only read only
|
63
|
+
## fix: also add author= why? why not???
|
64
|
+
def author() @authors[0]; end
|
42
65
|
|
43
|
-
## note: guid is an alias for id; todo/fix: reverse - make guid an alias of id
|
44
|
-
alias :id :guid
|
45
|
-
alias :id= :guid=
|
46
66
|
|
67
|
+
attr_accessor :tags
|
68
|
+
def tags?() @tags && @tags.size > 0; end
|
47
69
|
|
48
|
-
|
49
|
-
##
|
70
|
+
def initialize
|
71
|
+
## note: make authors, tags empty arrays on startup (e.g. not nil)
|
72
|
+
@authors = []
|
73
|
+
@tags = []
|
74
|
+
end
|
50
75
|
|
51
76
|
end # class Item
|
52
77
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FeedParser
|
4
|
+
|
5
|
+
class Tag
|
6
|
+
|
7
|
+
attr_accessor :name
|
8
|
+
## note: title n term are aliases for name
|
9
|
+
alias :title :name
|
10
|
+
alias :title= :name=
|
11
|
+
|
12
|
+
alias :term :name
|
13
|
+
alias :term= :name=
|
14
|
+
|
15
|
+
|
16
|
+
attr_accessor :scheme ## use scheme_url -why? why not? is it always a url/uri??
|
17
|
+
## note: domain (rss) is an alias for scheme (atom)
|
18
|
+
alias :domain :scheme
|
19
|
+
alias :domain= :scheme=
|
20
|
+
|
21
|
+
end # class Tag
|
22
|
+
|
23
|
+
end # module FeedParser
|
data/lib/feedparser/version.rb
CHANGED
@@ -0,0 +1,125 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rss version="2.0" xml:base="https://www.nostarch.com/frontpage_comingsoon"
|
3
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
4
|
+
xmlns:atom="http://www.w3.org/2005/Atom">
|
5
|
+
<channel>
|
6
|
+
<title>No Starch Press - Coming Soon</title>
|
7
|
+
<link>https://www.nostarch.com/frontpage_comingsoon</link>
|
8
|
+
<description>Keep an eye on what's coming out down the line.</description>
|
9
|
+
<language>en</language>
|
10
|
+
<atom:link href="https://www.nostarch.com/feeds/comingsoon.xml?startat=tcpip" rel="self" type="application/rss+xml" />
|
11
|
+
<item>
|
12
|
+
<title>PoC||GTFO</title>
|
13
|
+
<link>https://www.nostarch.com/gtfo</link>
|
14
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/gtfo"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/GTFO_cover.png?itok=DUUsVJxz" width="168" height="225" alt="PoC||GTFO" title="PoC||GTFO" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="https://www.nostarch.com/gtfo">PoC||GTFO</a> is a compilation of the wildly popular hacker zine of the same name. Contributions range from humorous poems to deeply technical essays.</p>
|
15
|
+
</div></div></div></description>
|
16
|
+
<pubDate>Tue, 11 Apr 2017 23:50:54 +0000</pubDate>
|
17
|
+
<dc:creator>Caitlin Griffin</dc:creator>
|
18
|
+
<guid isPermaLink="false">423 at https://www.nostarch.com</guid>
|
19
|
+
</item>
|
20
|
+
<item>
|
21
|
+
<title>Coding iPhone Apps for Kids</title>
|
22
|
+
<link>https://www.nostarch.com/iphoneappsforkids</link>
|
23
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/iphoneappsforkids"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/CodingiPhoneAppsforKids_cover.png?itok=zfRGgmaL" width="170" height="225" alt="Coding iPhone Apps for Kids" title="Coding iPhone Apps for Kids" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="/iphoneappsforkids">Coding iPhone Apps for Kids</a> teaches you how to program the iOS apps and games you’ve always wanted to make! <i>PDF Available Now!</i></p>
|
24
|
+
</div></div></div></description>
|
25
|
+
<pubDate>Fri, 11 Mar 2016 19:07:21 +0000</pubDate>
|
26
|
+
<dc:creator>Caitlin Griffin</dc:creator>
|
27
|
+
<guid isPermaLink="false">371 at https://www.nostarch.com</guid>
|
28
|
+
</item>
|
29
|
+
<item>
|
30
|
+
<title>Gray Hat C#</title>
|
31
|
+
<link>https://www.nostarch.com/grayhatcsharp</link>
|
32
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/grayhatcsharp"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/GrayHatC_cover.png?itok=oFuFmPd9" width="170" height="225" alt="Gray Hat C#" title="Gray Hat C#" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="https://www.nostarch.com/GrayHatCSharp">Gray Hat C#</a> shows you how to use C#'s powerful set of core libraries to create and automate security tools. <i>PDF Available Now!</i></p>
|
33
|
+
</div></div></div></description>
|
34
|
+
<pubDate>Wed, 27 Jul 2016 18:35:33 +0000</pubDate>
|
35
|
+
<dc:creator>Caitlin Griffin</dc:creator>
|
36
|
+
<guid isPermaLink="false">389 at https://www.nostarch.com</guid>
|
37
|
+
</item>
|
38
|
+
<item>
|
39
|
+
<title>The Arduino Inventor's Guide</title>
|
40
|
+
<link>https://www.nostarch.com/sparkfunarduino</link>
|
41
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/sparkfunarduino"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/ArduinoInventor%27sGuide_cover_0.png?itok=eSSQoSei" width="170" height="225" alt="The Arduino Inventor&#039;s Guide" title="The Arduino Inventor&#039;s Guide" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="/sparkfunarduino">The Arduino Inventor's Guide</a> is a hands-on introduction to exploring electronics with Arduino for total beginners. <i>Now Available in Early Access!</i></p>
|
42
|
+
</div></div></div></description>
|
43
|
+
<pubDate>Tue, 19 May 2015 23:41:36 +0000</pubDate>
|
44
|
+
<dc:creator>Anonymous</dc:creator>
|
45
|
+
<guid isPermaLink="false">346 at https://www.nostarch.com</guid>
|
46
|
+
</item>
|
47
|
+
<item>
|
48
|
+
<title>The Manga Guide to Microprocessors</title>
|
49
|
+
<link>https://www.nostarch.com/microprocessors</link>
|
50
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/microprocessors"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/MangaMicroprocessors_cover_0.png?itok=MxmdxH9e" width="170" height="225" alt="The Manga Guide to Microprocessors" title="The Manga Guide to Microprocessors" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="/microprocessors">The Manga Guide to Microprocessors</a> is a comic guide to microprocessors, computer architecture, and digital operations. <i>Now Available in Early Access!</i></p>
|
51
|
+
</div></div></div></description>
|
52
|
+
<pubDate>Mon, 24 Oct 2016 20:43:55 +0000</pubDate>
|
53
|
+
<dc:creator>ahariri</dc:creator>
|
54
|
+
<guid isPermaLink="false">393 at https://www.nostarch.com</guid>
|
55
|
+
</item>
|
56
|
+
<item>
|
57
|
+
<title>Arduino Project Handbook, Vol. 2</title>
|
58
|
+
<link>https://www.nostarch.com/arduinohandbook2</link>
|
59
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/arduinohandbook2"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/ArduinoProjectHandbookII_cover.png?itok=FkF3sw-p" width="170" height="225" alt="Arduino Project Handbook Vol. 2" title="Arduino Project Handbook Vol. 2" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="/arduinohandbook2">Arduino Project Handbook, Vol. 2</a> is a full-color guide to building 25 fun and practical projects with the low-cost Arduino microcontroller. <i>Now Available in Early Access!</i></p>
|
60
|
+
</div></div></div></description>
|
61
|
+
<pubDate>Mon, 24 Oct 2016 21:24:45 +0000</pubDate>
|
62
|
+
<dc:creator>ahariri</dc:creator>
|
63
|
+
<guid isPermaLink="false">394 at https://www.nostarch.com</guid>
|
64
|
+
</item>
|
65
|
+
<item>
|
66
|
+
<title>Think Like a Programmer, Python Edition</title>
|
67
|
+
<link>https://www.nostarch.com/thinkpython</link>
|
68
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/thinkpython"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/ThinkLikeaProgrammerPython_cover.png?itok=1yCoVJfA" width="170" height="225" alt="Think Like a Programmer, Python Edition" title="Think Like a Programmer, Python Edition" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p>The Python edition of <a href="https://www.nostarch.com/thinkpython">Think Like a Programmer</a> will teach you how to solve problems with programming.</p>
|
69
|
+
</div></div></div></description>
|
70
|
+
<pubDate>Fri, 10 Mar 2017 23:50:24 +0000</pubDate>
|
71
|
+
<dc:creator>ahariri</dc:creator>
|
72
|
+
<guid isPermaLink="false">399 at https://www.nostarch.com</guid>
|
73
|
+
</item>
|
74
|
+
<item>
|
75
|
+
<title>Computers for Seniors</title>
|
76
|
+
<link>https://www.nostarch.com/computersforseniors</link>
|
77
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/computersforseniors"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/ComputersforSeniors_cover.png?itok=sWPaSVC7" width="170" height="225" alt="Computers for Seniors" title="Computers for Seniors" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="https://www.nostarch.com/computersforseniors">Computers for Seniors</a> is a step-by-step guide to learning basic computer skills.</p>
|
78
|
+
</div></div></div></description>
|
79
|
+
<pubDate>Wed, 13 Apr 2016 20:07:07 +0000</pubDate>
|
80
|
+
<dc:creator>Caitlin Griffin</dc:creator>
|
81
|
+
<guid isPermaLink="false">375 at https://www.nostarch.com</guid>
|
82
|
+
</item>
|
83
|
+
<item>
|
84
|
+
<title>Game Console</title>
|
85
|
+
<link>https://www.nostarch.com/gameconsole</link>
|
86
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/gameconsole"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/gameconsole_cover.png?itok=S9JH4c1z" width="176" height="225" alt="The Game Console" title="The Game Console" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><b><a href="/gameconsole">The Game Console</a></b> is a visual history of video game technology, with gorgeous photos of more than 80 video game consoles manufactured since 1972.</p>
|
87
|
+
</div></div></div></description>
|
88
|
+
<pubDate>Sat, 09 Jan 2016 00:31:43 +0000</pubDate>
|
89
|
+
<dc:creator>Caitlin Griffin</dc:creator>
|
90
|
+
<guid isPermaLink="false">362 at https://www.nostarch.com</guid>
|
91
|
+
</item>
|
92
|
+
<item>
|
93
|
+
<title>Serious Cryptography</title>
|
94
|
+
<link>https://www.nostarch.com/seriouscrypto</link>
|
95
|
+
<description><div class="field field-name-field-image-cache field-type-image field-label-hidden"><div class="field-items"><div class="field-item even"><a href="/seriouscrypto"><img class="img-responsive" src="https://www.nostarch.com/sites/default/files/styles/uc_product/public/SeriousCrypto_cover_0.png?itok=s0OdQ-Pl" width="170" height="225" alt="Serious Cryptography" title="Serious Cryptography" /></a></div></div></div><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even"><p><a href="https://www.nostarch.com/SeriousCrypto">Serious Cryptography</a> is a practical guide to the past, present, and future of cryptographic systems and algorithms. <i>Now Available in Early Access!</i></p>
|
96
|
+
</div></div></div></description>
|
97
|
+
<pubDate>Tue, 25 Apr 2017 22:25:46 +0000</pubDate>
|
98
|
+
<dc:creator>Caitlin Griffin</dc:creator>
|
99
|
+
<guid isPermaLink="false">428 at https://www.nostarch.com</guid>
|
100
|
+
</item>
|
101
|
+
</channel>
|
102
|
+
</rss>
|
103
|
+
|
104
|
+
---
|
105
|
+
|
106
|
+
feed.format: rss 2.0
|
107
|
+
feed.title: No Starch Press - Coming Soon
|
108
|
+
feed.url: https://www.nostarch.com/frontpage_comingsoon
|
109
|
+
feed.summary: Keep an eye on what's coming out down the line.
|
110
|
+
|
111
|
+
|
112
|
+
feed.items.size: >>> 10
|
113
|
+
|
114
|
+
feed.items[0].title: PoC||GTFO
|
115
|
+
feed.items[0].url: https://www.nostarch.com/gtfo
|
116
|
+
feed.items[0].guid: 423 at https://www.nostarch.com
|
117
|
+
feed.items[0].updated: >>> DateTime.new( 2017, 4, 11, 23, 50, 54 )
|
118
|
+
|
119
|
+
feed.items[1].title: Coding iPhone Apps for Kids
|
120
|
+
feed.items[1].url: https://www.nostarch.com/iphoneappsforkids
|
121
|
+
feed.items[1].guid: 371 at https://www.nostarch.com
|
122
|
+
feed.items[1].updated: >>> DateTime.new( 2016, 3, 11, 19, 7, 21 )
|
123
|
+
|
124
|
+
|
125
|
+
>>> pp feed.items[0].summary
|