saper 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/Rakefile +6 -6
  4. data/bin/saper +17 -36
  5. data/lib/saper.rb +63 -20
  6. data/lib/saper/actions/append_with.rb +1 -1
  7. data/lib/saper/actions/convert_to_html.rb +1 -1
  8. data/lib/saper/actions/convert_to_json.rb +6 -2
  9. data/lib/saper/actions/convert_to_markdown.rb +1 -1
  10. data/lib/saper/actions/convert_to_time.rb +38 -1
  11. data/lib/saper/actions/convert_to_xml.rb +1 -1
  12. data/lib/saper/actions/create_atom.rb +6 -2
  13. data/lib/saper/actions/fetch.rb +3 -2
  14. data/lib/saper/actions/fetch_with_token.rb +18 -0
  15. data/lib/saper/actions/find.rb +1 -1
  16. data/lib/saper/actions/find_first.rb +1 -1
  17. data/lib/saper/actions/get_attribute.rb +7 -2
  18. data/lib/saper/actions/get_contents.rb +1 -1
  19. data/lib/saper/actions/get_text.rb +1 -1
  20. data/lib/saper/actions/nothing.rb +11 -0
  21. data/lib/saper/actions/prepend_with.rb +2 -2
  22. data/lib/saper/actions/remove_after.rb +2 -2
  23. data/lib/saper/actions/remove_before.rb +2 -2
  24. data/lib/saper/actions/remove_matching.rb +2 -2
  25. data/lib/saper/actions/remove_tags.rb +1 -1
  26. data/lib/saper/actions/replace.rb +1 -1
  27. data/lib/saper/actions/run_recipe.rb +2 -2
  28. data/lib/saper/actions/run_recipe_and_save.rb +3 -3
  29. data/lib/saper/actions/save.rb +2 -2
  30. data/lib/saper/actions/select_matching.rb +2 -2
  31. data/lib/saper/actions/set_input.rb +1 -1
  32. data/lib/saper/actions/skip_tags.rb +1 -1
  33. data/lib/saper/actions/split.rb +1 -1
  34. data/lib/saper/arguments/attribute.rb +6 -0
  35. data/lib/saper/arguments/recipe.rb +12 -6
  36. data/lib/saper/arguments/service.rb +12 -0
  37. data/lib/saper/arguments/text.rb +1 -0
  38. data/lib/saper/arguments/timezone.rb +2 -1
  39. data/lib/saper/arguments/url.rb +12 -0
  40. data/lib/saper/arguments/variable.rb +2 -1
  41. data/lib/saper/arguments/xpath.rb +2 -1
  42. data/lib/saper/core/action.rb +43 -13
  43. data/lib/saper/core/argument.rb +30 -14
  44. data/lib/saper/core/browser.rb +29 -28
  45. data/lib/saper/core/dsl.rb +14 -16
  46. data/lib/saper/core/error.rb +1 -1
  47. data/lib/saper/core/item.rb +2 -2
  48. data/lib/saper/core/keychain.rb +58 -5
  49. data/lib/saper/core/namespace.rb +15 -18
  50. data/lib/saper/core/recipe.rb +53 -12
  51. data/lib/saper/core/result.rb +72 -0
  52. data/lib/saper/core/runtime.rb +44 -177
  53. data/lib/saper/core/stack.rb +57 -0
  54. data/lib/saper/items/atom.rb +18 -1
  55. data/lib/saper/items/document.rb +39 -19
  56. data/lib/saper/items/html.rb +52 -7
  57. data/lib/saper/items/json.rb +19 -1
  58. data/lib/saper/items/markdown.rb +14 -4
  59. data/lib/saper/items/nothing.rb +6 -0
  60. data/lib/saper/items/text.rb +28 -3
  61. data/lib/saper/items/time.rb +25 -2
  62. data/lib/saper/items/url.rb +8 -2
  63. data/lib/saper/items/xml.rb +51 -11
  64. data/lib/{lib → saper/patches}/mechanize.rb +0 -0
  65. data/lib/{lib → saper/patches}/nokogiri.rb +0 -0
  66. data/lib/saper/version.rb +2 -2
  67. data/spec/actions/append_with_spec.rb +29 -52
  68. data/spec/actions/convert_to_html_spec.rb +13 -30
  69. data/spec/actions/convert_to_json_spec.rb +13 -30
  70. data/spec/actions/convert_to_markdown_spec.rb +17 -19
  71. data/spec/actions/convert_to_time_spec.rb +25 -43
  72. data/spec/actions/convert_to_xml_spec.rb +15 -11
  73. data/spec/actions/create_atom_spec.rb +11 -19
  74. data/spec/actions/fetch_spec.rb +3 -8
  75. data/spec/actions/find_first_spec.rb +38 -40
  76. data/spec/actions/find_spec.rb +23 -39
  77. data/spec/actions/get_attribute_spec.rb +30 -3
  78. data/spec/actions/{get_contents.rb → get_contents_spec.rb} +0 -0
  79. data/spec/actions/{get_text.rb → get_text_spec.rb} +0 -0
  80. data/spec/actions/nothing_spec.rb +7 -0
  81. data/spec/actions/prepend_with_spec.rb +31 -18
  82. data/spec/actions/{remove_after.rb → remove_after_spec.rb} +0 -0
  83. data/spec/actions/{remove_before.rb → remove_before_spec.rb} +0 -0
  84. data/spec/actions/remove_matching_spec.rb +7 -0
  85. data/spec/actions/remove_tags_spec.rb +7 -0
  86. data/spec/actions/run_recipe_and_save_spec.rb +7 -0
  87. data/spec/actions/run_recipe_spec.rb +7 -0
  88. data/spec/arguments/attribute_spec.rb +7 -0
  89. data/spec/arguments/recipe_spec.rb +7 -0
  90. data/spec/arguments/text_spec.rb +7 -0
  91. data/spec/arguments/timezone_spec.rb +7 -0
  92. data/spec/arguments/variable_spec.rb +7 -0
  93. data/spec/arguments/xpath_spec.rb +7 -0
  94. data/spec/core/action_spec.rb +13 -142
  95. data/spec/core/argument_spec.rb +38 -71
  96. data/spec/core/browser_spec.rb +18 -3
  97. data/spec/core/dsl_spec.rb +1 -1
  98. data/spec/core/item_spec.rb +1 -1
  99. data/spec/core/namespace_spec.rb +0 -11
  100. data/spec/core/recipe_spec.rb +54 -77
  101. data/spec/core/result_spec.rb +7 -0
  102. data/spec/core/runtime_spec.rb +20 -151
  103. data/spec/core/stack_spec.rb +7 -0
  104. data/spec/integration/simple_invalid_spec.rb +39 -0
  105. data/spec/integration/simple_valid_spec.rb +39 -0
  106. data/spec/items/atom_spec.rb +6 -1
  107. data/spec/items/document_spec.rb +93 -15
  108. data/spec/items/html_spec.rb +45 -28
  109. data/spec/items/json_spec.rb +10 -10
  110. data/spec/items/markdown_spec.rb +24 -3
  111. data/spec/items/nothing_spec.rb +1 -1
  112. data/spec/items/text_spec.rb +13 -41
  113. data/spec/items/time_spec.rb +25 -4
  114. data/spec/items/url_spec.rb +1 -7
  115. data/spec/items/xml_spec.rb +46 -39
  116. data/spec/spec_helper.rb +2 -21
  117. metadata +63 -60
  118. data/lib/lib/json_search.rb +0 -54
  119. data/spec/actions/run_recipe_and_save_spec.tmp.rb +0 -52
  120. data/spec/actions/run_recipe_spec.tmp.rb +0 -53
@@ -2,12 +2,17 @@ module Saper
2
2
  module Items
3
3
  class HTML < Item
4
4
 
5
+ # @todo
5
6
  def self.new(item)
6
7
  super case item
7
8
  when Nokogiri::XML::Element
8
9
  item
10
+ when Nokogiri::XML::Document
11
+ item
9
12
  when Nokogiri::HTML
10
13
  item
14
+ when Document
15
+ parse(item.body, item.uri, item.charset)
11
16
  when Text
12
17
  parse(item.to_s)
13
18
  when String
@@ -17,14 +22,23 @@ module Saper
17
22
  end
18
23
  end
19
24
 
25
+ # @todo
20
26
  def self.parse(string, uri = nil, charset = nil)
27
+ if string.empty?
28
+ raise(InvalidItem, string)
29
+ end
21
30
  begin
31
+ # Nokogiri adds an additional body tag for strings that don't
32
+ # have one. Should probably use Nokogiri::HTML.fragment in that
33
+ # case, but it breaks the search function:
34
+ # https://github.com/sparklemotion/nokogiri/issues/572
22
35
  Nokogiri::HTML.parse(string, uri, charset)
23
36
  rescue
24
37
  raise(InvalidItem, string)
25
38
  end
26
39
  end
27
40
 
41
+ # @todo
28
42
  def initialize(noko)
29
43
  @noko = noko
30
44
  # Force UTF-8 encoding
@@ -32,48 +46,79 @@ module Saper
32
46
  @noko.document.encoding = 'UTF-8'
33
47
  end
34
48
 
49
+ # @todo
50
+ def dup
51
+ HTML.new(@noko.dup)
52
+ end
53
+
54
+ # @todo
55
+ def ==(other)
56
+ to_s == other.to_s
57
+ end
58
+
59
+ # @todo
35
60
  def name
36
61
  @noko.name
37
62
  end
38
63
 
64
+ # @todo
39
65
  def [](name)
40
- @noko[name]
66
+ @noko.has_attribute?(name) ? Text.new(@noko[name]) : nil
41
67
  end
42
68
 
69
+ # @todo
43
70
  def find(xpath)
44
71
  find_all(xpath).first
45
72
  end
46
73
 
74
+ # @todo
47
75
  def find_all(xpath)
48
76
  @noko.search(xpath).map { |element| HTML.new(element) }
49
77
  end
50
78
 
51
- def remove_children_with_content(xpath)
79
+ # @todo
80
+ def remove_children_with_content!(xpath)
52
81
  @noko.search(xpath).each { |item| item.remove }; self
53
82
  end
54
83
 
55
- def remove_children_preserving_content(xpath)
84
+ # @todo
85
+ def remove_children_with_content(xpath)
86
+ dup.remove_children_with_content!(xpath)
87
+ end
88
+
89
+ # @todo
90
+ def remove_children_preserving_content!(xpath)
56
91
  @noko.search(xpath).each { |item| item.replace(item.children) }; self
57
92
  end
93
+
94
+ # @todo
95
+ def remove_children_preserving_content(xpath)
96
+ dup.remove_children_preserving_content!(xpath)
97
+ end
58
98
 
99
+ # @todo
59
100
  def inner_html
60
- @noko.inner_html
101
+ Text.new @noko.inner_html.gsub("\n","")
61
102
  end
62
103
 
104
+ # @todo
63
105
  def inner_text
64
- @noko.inner_text
106
+ Text.new @noko.inner_text
65
107
  end
66
108
 
109
+ # @todo
67
110
  def to_markdown
68
111
  Markdown.new self
69
112
  end
70
113
 
114
+ # @todo
71
115
  def to_native
72
- inner_html
116
+ inner_html.to_native
73
117
  end
74
118
 
119
+ # @todo
75
120
  def to_s
76
- inner_html
121
+ @noko.is_a?(Nokogiri::HTML::Document) ? to_native : @noko.to_s
77
122
  end
78
123
 
79
124
  end
@@ -2,6 +2,7 @@ module Saper
2
2
  module Items
3
3
  class JSON < Item
4
4
 
5
+ # @todo
5
6
  def self.new(item, bypass = false)
6
7
  super case item
7
8
  when Text
@@ -15,6 +16,7 @@ module Saper
15
16
  end
16
17
  end
17
18
 
19
+ # @todo
18
20
  def self.parse(string)
19
21
  begin
20
22
  ::JSON.parse(string)
@@ -23,28 +25,44 @@ module Saper
23
25
  end
24
26
  end
25
27
 
28
+ # @todo
26
29
  def initialize(hash)
27
30
  @hash = hash
28
31
  end
29
32
 
33
+ # @todo
34
+ def ==(other)
35
+ @hash == other
36
+ end
37
+
38
+ # @todo
30
39
  def find(xpath)
31
40
  find_all(xpath).first
32
41
  end
33
42
 
43
+ # @todo
34
44
  def find_all(xpath)
35
- sanitize JSONSearch.find(@hash, xpath)
45
+ sanitize JPath.find(@hash, xpath)
36
46
  end
37
47
 
48
+ # @todo
38
49
  def to_s
39
50
  ::JSON.dump(@hash)
40
51
  end
41
52
 
53
+ # @todo
54
+ def to_json(*a)
55
+ a.empty? ? self : @hash
56
+ end
57
+
58
+ # @todo
42
59
  def to_native
43
60
  to_s
44
61
  end
45
62
 
46
63
  private
47
64
 
65
+ # @todo
48
66
  def sanitize(item)
49
67
  case item
50
68
  when Hash
@@ -2,33 +2,43 @@ module Saper
2
2
  module Items
3
3
  class Markdown < Item
4
4
 
5
+ # @todo
5
6
  def self.new(item)
6
7
  super case item
7
8
  when HTML
8
- parse(item.inner_html)
9
+ parse(item.to_s)
9
10
  else
10
11
  raise(InvalidItem, item)
11
12
  end
12
13
  end
13
14
 
15
+ # @todo
14
16
  def self.parse(string)
15
17
  begin
16
- ::ReverseMarkdown.convert(string).strip
18
+ ::ReverseMarkdown.convert(string, unknown_tags: :drop).strip
17
19
  rescue
18
20
  raise(InvalidItem, string)
19
21
  end
20
22
  end
21
23
 
24
+ # @todo
22
25
  def initialize(string)
23
26
  @string = string
24
27
  end
25
28
 
29
+ # @todo
30
+ def ==(other)
31
+ to_s == other.to_s
32
+ end
33
+
34
+ # @todo
26
35
  def to_s
27
- @string
36
+ to_native
28
37
  end
29
38
 
39
+ # @todo
30
40
  def to_native
31
- to_s
41
+ @string
32
42
  end
33
43
 
34
44
  end
@@ -2,14 +2,20 @@ module Saper
2
2
  module Items
3
3
  class Nothing < Item
4
4
 
5
+ # @todo
5
6
  def nil?
6
7
  true
7
8
  end
8
9
 
10
+ # @todo
9
11
  def to_native
10
12
  nil
11
13
  end
12
14
 
15
+ def to_s
16
+ 'nil'
17
+ end
18
+
13
19
  end
14
20
  end
15
21
  end
@@ -2,6 +2,7 @@ module Saper
2
2
  module Items
3
3
  class Text < Item
4
4
 
5
+ # @todo
5
6
  def self.new(item)
6
7
  super case item
7
8
  when String
@@ -13,40 +14,64 @@ module Saper
13
14
  end
14
15
  end
15
16
 
17
+ # @todo
16
18
  def initialize(string)
17
19
  @string = string
18
20
  end
19
21
 
20
- def split(separator, number = nil)
22
+ # @todo
23
+ def ==(other)
24
+ hash == other.hash
25
+ end
26
+
27
+ # @todo
28
+ def hash
29
+ to_s.hash
30
+ end
31
+
32
+ # @todo
33
+ def empty?
34
+ @string.empty?
35
+ end
36
+
37
+ # @todo
38
+ def split(separator, number = -1)
21
39
  @string.split(separator, number)
22
40
  end
23
41
 
42
+ # @todo
24
43
  def gsub(*args, &block)
25
44
  @string.gsub(*args, &block)
26
45
  end
27
46
 
47
+ # @todo
28
48
  def to_xml
29
49
  XML.new(self)
30
50
  end
31
51
 
52
+ # @todo
32
53
  def to_html
33
54
  HTML.new(self)
34
55
  end
35
56
 
57
+ # @todo
36
58
  def to_json
37
59
  JSON.new(self)
38
60
  end
39
61
 
62
+ # @todo
40
63
  def to_time(format, tz = nil)
41
64
  Time.new(self, format, tz)
42
65
  end
43
66
 
67
+ # @todo
44
68
  def to_s
45
- @string
69
+ to_native
46
70
  end
47
71
 
72
+ # @todo
48
73
  def to_native
49
- to_s
74
+ @string
50
75
  end
51
76
 
52
77
  end
@@ -2,17 +2,21 @@ module Saper
2
2
  module Items
3
3
  class Time < Item
4
4
 
5
- def self.new(item, format, tz = nil)
5
+ # @todo
6
+ def self.new(item, format = nil, tz = nil)
6
7
  super case item
7
8
  when Text
8
9
  parse(item.to_s, format, tz)
9
10
  when String
10
11
  parse(item, format, tz)
12
+ when Vremya
13
+ item
11
14
  else
12
15
  raise(InvalidItem, item)
13
16
  end
14
17
  end
15
18
 
19
+ # @todo
16
20
  def self.parse(string, format, tz = nil)
17
21
  begin
18
22
  ::Vremya.parse(string, format, tz)
@@ -21,20 +25,39 @@ module Saper
21
25
  end
22
26
  end
23
27
 
28
+ # @todo
29
+ def self.now(tz = nil)
30
+ new ::Vremya.now(tz)
31
+ end
32
+
33
+ # @todo
24
34
  def initialize(vremya)
25
35
  @vremya = vremya
26
36
  end
27
37
 
38
+ # @todo
39
+ def ==(other)
40
+ to_i == other.to_i
41
+ end
42
+
43
+ # @todo
28
44
  def to_s
29
45
  @vremya.iso8601
30
46
  end
31
47
 
48
+ # @todo
32
49
  def to_native
33
50
  @vremya.to_time
34
51
  end
35
52
 
53
+ # @todo
54
+ def to_i
55
+ to_native.to_i
56
+ end
57
+
58
+ # @todo
36
59
  def serialize
37
- to_s
60
+ @vremya.to_utc.to_time
38
61
  end
39
62
 
40
63
  end
@@ -2,6 +2,7 @@ module Saper
2
2
  module Items
3
3
  class URL < Item
4
4
 
5
+ # @todo
5
6
  def self.new(item)
6
7
  super case item
7
8
  when Text
@@ -13,22 +14,27 @@ module Saper
13
14
  end
14
15
  end
15
16
 
17
+ # @todo
16
18
  def self.parse(string)
17
19
  unless string =~ /^#{URI::regexp}$/
18
20
  raise(InvalidItem, string)
19
21
  end
22
+ string
20
23
  end
21
24
 
25
+ # @todo
22
26
  def initialize(url)
23
27
  @url = url
24
28
  end
25
29
 
30
+ # @todo
26
31
  def to_s
27
- @url
32
+ to_native
28
33
  end
29
34
 
35
+ # @todo
30
36
  def to_native
31
- to_s
37
+ @url
32
38
  end
33
39
 
34
40
  end
@@ -2,10 +2,15 @@ module Saper
2
2
  module Items
3
3
  class XML < Item
4
4
 
5
+ # @todo
5
6
  def self.new(item)
6
7
  super case item
7
8
  when Nokogiri::XML
8
9
  item
10
+ when Nokogiri::XML::Document
11
+ item
12
+ when Nokogiri::XML::Element
13
+ item
9
14
  when Text
10
15
  parse(item.to_s)
11
16
  when String
@@ -15,7 +20,11 @@ module Saper
15
20
  end
16
21
  end
17
22
 
23
+ # @todo
18
24
  def self.parse(string, uri = nil, charset = nil)
25
+ if string.empty?
26
+ raise(InvalidItem, string)
27
+ end
19
28
  begin
20
29
  Nokogiri::XML.parse(string, uri, charset)
21
30
  rescue
@@ -23,6 +32,7 @@ module Saper
23
32
  end
24
33
  end
25
34
 
35
+ # @todo
26
36
  def initialize(noko)
27
37
  @noko = noko
28
38
  # Force UTF-8 encoding
@@ -30,46 +40,76 @@ module Saper
30
40
  @noko.document.encoding = 'UTF-8'
31
41
  end
32
42
 
43
+ # @todo
44
+ def dup
45
+ XML.new(@noko.dup)
46
+ end
47
+
48
+ # @todo
49
+ def ==(other)
50
+ to_s == other.to_s
51
+ end
52
+
53
+ # @todo
33
54
  def name
34
55
  @noko.name
35
56
  end
36
57
 
58
+ # @todo
37
59
  def [](name)
38
- @noko[name]
60
+ @noko.has_attribute?(name) ? Text.new(@noko[name]) : nil
39
61
  end
40
62
 
63
+ # @todo
41
64
  def find(xpath)
42
65
  find_all(xpath).first
43
66
  end
44
67
 
68
+ # @todo
45
69
  def find_all(xpath)
46
70
  @noko.search(xpath).map { |element| XML.new(element) }
47
71
  end
48
72
 
49
- def remove_children_with_content(xpath)
73
+ # @todo
74
+ def remove_children_with_content!(xpath)
50
75
  @noko.search(xpath).each { |item| item.remove }; self
51
76
  end
52
77
 
53
- def remove_children_preserving_content(xpath)
54
- @noko.search(xpath).each { |item| item.replace(item.children) }; self
78
+ # @todo
79
+ def remove_children_with_content(xpath)
80
+ dup.remove_children_with_content!(xpath)
55
81
  end
56
82
 
57
- def inner_html
58
- @noko.inner_html
83
+ # @todo
84
+ def remove_children_preserving_content!(xpath)
85
+ @noko.search(xpath).each { |item| item.replace(item.children) }; self
86
+ end
87
+
88
+ # @todo
89
+ def remove_children_preserving_content(xpath)
90
+ dup.remove_children_preserving_content!(xpath)
59
91
  end
60
92
 
61
- def inner_text
62
- @noko.inner_text
93
+ # @todo
94
+ def inner_xml
95
+ Text.new @noko.inner_html
63
96
  end
64
97
 
65
- def to_s
66
- inner_html
98
+ # @todo
99
+ def inner_text
100
+ Text.new @noko.inner_text
67
101
  end
68
102
 
103
+ # @todo
69
104
  def to_native
70
- inner_html
105
+ inner_xml.to_native
71
106
  end
72
107
 
108
+ # @todo
109
+ def to_s
110
+ @noko.is_a?(Nokogiri::XML::Document) ? to_native : @noko.to_s
111
+ end
112
+
73
113
  end
74
114
  end
75
115
  end