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
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :text
6
6
  accepts :text, :returns => :text
7
7
 
8
- run do |input, string|
9
- "%s%s" % [string, input]
8
+ run do |runtime, input, string|
9
+ Items::Text.new "%s%s" % [string, input]
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :text
6
6
  accepts :text, :returns => :text
7
7
 
8
- run do |input, separator|
9
- input.split(separator, 2).first
8
+ run do |runtime, input, separator|
9
+ Items::Text.new input.split(separator, 2).first
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :text
6
6
  accepts :text, :returns => :text
7
7
 
8
- run do |input, separator|
9
- input.split(separator, 2).last
8
+ run do |runtime, input, separator|
9
+ Items::Text.new input.split(separator, 2).last
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :text
6
6
  accepts :text, :returns => :text
7
7
 
8
- run do |input, pattern|
9
- input.to_s =~ Regexp.new(pattern) ? nil : input
8
+ run do |runtime, input, pattern|
9
+ input.to_s =~ Regexp.new(pattern) ? Items::Nothing.new : input
10
10
  end
11
11
 
12
12
  end
@@ -6,7 +6,7 @@ module Saper
6
6
  accepts :xml, :returns => :xml
7
7
  accepts :html, :returns => :html
8
8
 
9
- run do |input, xpath|
9
+ run do |runtime, input, xpath|
10
10
  input.remove_children_with_content(xpath)
11
11
  end
12
12
 
@@ -6,7 +6,7 @@ module Saper
6
6
  argument :text
7
7
  accepts :text, :returns => :text
8
8
 
9
- run do |input, what, with|
9
+ run do |runtime, input, what, with|
10
10
  input.gsub(what, with)
11
11
  end
12
12
 
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :recipe
6
6
  accepts :anything, :returns => Proc.new { |instance| nil } # TODO
7
7
 
8
- run do |input, subrecipe|
9
- recipe(subrecipe, input)
8
+ run do |runtime, input, subrecipe|
9
+ subrecipe.run(input).to_saper
10
10
  end
11
11
 
12
12
  # Overrides default logic
@@ -6,9 +6,9 @@ module Saper
6
6
  argument :recipe
7
7
  accepts :anything
8
8
 
9
- run do |input, variable, subrecipe|
10
- result = recipe(subrecipe, input)
11
- self[variable] = result unless result.nil?
9
+ run do |runtime, input, variable, subrecipe|
10
+ result = subrecipe.run(input).to_saper
11
+ runtime[variable] = result unless result.nil?
12
12
  input
13
13
  end
14
14
 
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :variable
6
6
  accepts :anything
7
7
 
8
- run do |input, variable|
9
- self[variable] = input
8
+ run do |runtime, input, variable|
9
+ runtime[variable] = input
10
10
  end
11
11
 
12
12
  end
@@ -5,8 +5,8 @@ module Saper
5
5
  argument :text
6
6
  accepts :text, :returns => :text
7
7
 
8
- run do |input, pattern|
9
- input.to_s =~ Regexp.new(pattern) ? input : nil
8
+ run do |runtime, input, pattern|
9
+ input.to_s =~ Regexp.new(pattern) ? input : Items::Nothing.new
10
10
  end
11
11
 
12
12
  end
@@ -5,7 +5,7 @@ module Saper
5
5
  argument :text
6
6
  accepts :anything, :returns => :text
7
7
 
8
- run do |input, string|
8
+ run do |runtime, input, string|
9
9
  string
10
10
  end
11
11
 
@@ -6,7 +6,7 @@ module Saper
6
6
  accepts :xml, :returns => :xml
7
7
  accepts :html, :returns => :html
8
8
 
9
- run do |input, xpath|
9
+ run do |runtime, input, xpath|
10
10
  input.remove_children_preserving_content(xpath)
11
11
  end
12
12
 
@@ -8,7 +8,7 @@ module Saper
8
8
  accepts :document, :returns => :text
9
9
  accepts :html, :returns => :html
10
10
 
11
- run do |input, separator|
11
+ run do |runtime, input, separator|
12
12
  case input
13
13
  when Items::HTML
14
14
  input.inner_html.split(separator).map { |string| Item.new(:text, string).to_html }
@@ -2,10 +2,16 @@ module Saper
2
2
  module Arguments
3
3
  class Attribute < Argument
4
4
 
5
+ # @todo
5
6
  def valid?(value)
6
7
  value.is_a?(Symbol) || value.is_a?(String)
7
8
  end
8
9
 
10
+ # @todo
11
+ def normalize(value)
12
+ value.to_s
13
+ end
14
+
9
15
  end
10
16
  end
11
17
  end
@@ -1,19 +1,24 @@
1
1
  module Saper
2
2
  module Arguments
3
3
  class Recipe < Argument
4
-
4
+
5
+ # @todo
5
6
  def valid?(value)
6
- value.is_a?(Symbol) || value.is_a?(String)
7
+ value.is_a?(Symbol) || value.is_a?(String) || value.is_a?(Numeric)
7
8
  end
8
9
 
10
+ # @todo
9
11
  def normalize(value)
10
12
  if value.is_a?(Recipe)
11
13
  return value
12
14
  end
13
- if value.is_a?(String)
14
- value = value.to_sym
15
+ if value.is_a?(Symbol)
16
+ value = value.to_s
17
+ end
18
+ if value.is_a?(Numeric)
19
+ value = value.to_s
15
20
  end
16
- unless value.is_a?(Symbol)
21
+ unless value.is_a?(String)
17
22
  raise InvalidArgument
18
23
  end
19
24
  if action.nil?
@@ -28,11 +33,12 @@ module Saper
28
33
  value
29
34
  end
30
35
 
31
- #
36
+ # @todo
32
37
  def serialize
33
38
  value.id
34
39
  end
35
40
 
41
+ # @todo
36
42
  def to_string
37
43
  value.id.inspect
38
44
  end
@@ -0,0 +1,12 @@
1
+ module Saper
2
+ module Arguments
3
+ class Service < Argument
4
+
5
+ # @todo
6
+ def valid?(value)
7
+ value.is_a?(Symbol) || value.is_a?(String)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -2,6 +2,7 @@ module Saper
2
2
  module Arguments
3
3
  class Text < Argument
4
4
 
5
+ # @todo
5
6
  def valid?(value)
6
7
  value.is_a?(String)
7
8
  end
@@ -1,7 +1,8 @@
1
1
  module Saper
2
2
  module Arguments
3
3
  class Timezone < Argument
4
-
4
+
5
+ # @todo
5
6
  def valid?(value)
6
7
  value.is_a?(String)
7
8
  end
@@ -0,0 +1,12 @@
1
+ module Saper
2
+ module Arguments
3
+ class URL < Argument
4
+
5
+ # @todo
6
+ def valid?(value)
7
+ value.is_a?(String)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -1,7 +1,8 @@
1
1
  module Saper
2
2
  module Arguments
3
3
  class Variable < Argument
4
-
4
+
5
+ # @todo
5
6
  def valid?(value)
6
7
  value.is_a?(String) || value.is_a?(Symbol)
7
8
  end
@@ -1,7 +1,8 @@
1
1
  module Saper
2
2
  module Arguments
3
3
  class XPath < Argument
4
-
4
+
5
+ # @todo
5
6
  def valid?(value)
6
7
  value.is_a?(String)
7
8
  end
@@ -52,7 +52,7 @@ module Saper
52
52
  return @types.nil? ? [] : @types.keys
53
53
  end
54
54
  if input == :anything
55
- return Item.subclasses.keys.map { |type| accepts(type.to_sym, options) }
55
+ return @types = {}
56
56
  end
57
57
  output = options[:returns] || input
58
58
  unless Item.exists?(input)
@@ -65,11 +65,35 @@ module Saper
65
65
  @types[input] = output
66
66
  end
67
67
 
68
+ # Returns `true` if action accepts no input.
69
+ # @return [Boolean]
70
+ def self.accepts_nothing?
71
+ @types.nil?
72
+ end
73
+
74
+ # Returns `true` if action accepts at least some kind of input.
75
+ # @return [Boolean]
76
+ def self.accepts_something?
77
+ !accepts_nothing? && !accepts_anything?
78
+ end
79
+
80
+ # Returns `true` if action accepts any kind of input.
81
+ # @return [Boolean]
82
+ def self.accepts_anything?
83
+ @types.empty?
84
+ end
85
+
68
86
  # Returns `true` if action accepts specified type as input.
69
87
  # @param type [Symbol]
70
88
  # @return [Boolean]
71
89
  def self.accepts?(type)
72
- @types.nil? ? false : @types.keys.include?(type)
90
+ if accepts_nothing?
91
+ return false
92
+ end
93
+ if accepts_anything?
94
+ return true
95
+ end
96
+ accepts.include?(type)
73
97
  end
74
98
 
75
99
  # Saves Proc that encapsulates action logic and will be used later for data processing.
@@ -116,8 +140,12 @@ module Saper
116
140
  end
117
141
  end
118
142
 
143
+ # @todo
119
144
  attr_reader :options
120
145
 
146
+ # @todo
147
+ attr_reader :arguments
148
+
121
149
  # Returns a new instance of Saper::Action.
122
150
  # @return [Saper::Action]
123
151
  def initialize(*args)
@@ -139,24 +167,26 @@ module Saper
139
167
  # @param input [object] input
140
168
  # @return [void] depends on action type
141
169
  def run(input = nil, runtime = nil)
170
+ runtime ||= Runtime.new
171
+ input = validate_input(input)
172
+ block.call(runtime, input, *args)
173
+ end
174
+
175
+ # @todo
176
+ def validate_input(input)
177
+ unless self.class.accepts_something?
178
+ return input
179
+ end
142
180
  unless input.is_a?(Item)
143
181
  input = self.class.accepts.map { |type| Item.try(type, input) }.compact.first
144
182
  end
145
183
  if input.nil?
146
- input = Items::Nothing.new
184
+ raise(InvalidInput, input)
147
185
  end
148
186
  unless self.class.accepts?(input.type)
149
187
  raise(InvalidInput, input)
150
188
  end
151
- if runtime.nil?
152
- begin
153
- block.call(input, *args)
154
- rescue NameError
155
- raise RuntimeMissing
156
- end
157
- else
158
- runtime.instance_exec(input, *args, &self.block)
159
- end
189
+ input
160
190
  end
161
191
 
162
192
  # Returns human readable action name.
@@ -198,7 +228,7 @@ module Saper
198
228
  # Returns Proc that encapsulates action logic (i.e. processes data).
199
229
  # @return [Proc]
200
230
  def block
201
- self.class.run || Proc.new { |input, *args| input }
231
+ self.class.run || Proc.new { |runtime, input, *args| input }
202
232
  end
203
233
 
204
234
  # Returns string representation of Action.
@@ -43,7 +43,11 @@ module Saper
43
43
  end
44
44
  end
45
45
 
46
- # @todo
46
+ # Returns a new instacne of Saper::Argument.
47
+ # @option opts[Object] :value
48
+ # @option opts[Saper::Action] :action
49
+ # @option opts[Boolean] :optional
50
+ # @return [Saper::Argument]
47
51
  def initialize(opts = {})
48
52
  @value = nil
49
53
  @opts = opts
@@ -52,7 +56,9 @@ module Saper
52
56
  end
53
57
  end
54
58
 
55
- # @todo
59
+ # Sets new value and returns self.
60
+ # @param value [Object]
61
+ # @return [self]
56
62
  def set(value)
57
63
  unless valid?(value)
58
64
  raise InvalidArgument, value
@@ -62,42 +68,52 @@ module Saper
62
68
  self
63
69
  end
64
70
 
65
- # @todo
71
+ # Returns true if supplied value is accepted by this argument type. Subclasses should override this method.
72
+ # @param value [Object]
73
+ # @return [Boolean]
66
74
  def valid?(value)
67
75
  true
68
76
  end
69
77
 
70
- # @todo
78
+ # Returns normalized value.
79
+ # Subclasses should overrid this method. Subclasses may override this method.
80
+ # @param value [Object]
81
+ # @param value [Object]
71
82
  def normalize(value)
72
83
  value
73
84
  end
74
85
 
75
- # @todo
86
+ # Returns argument value. Subclasses may override this method.
87
+ # @return [Object]
76
88
  def value
77
89
  @value
78
90
  end
79
91
 
80
- # @todo
92
+ # Returns serialized representation of argument's value. Subclasses may override this method.
81
93
  def serialize
82
94
  value
83
95
  end
84
96
 
85
- # @todo
97
+ # Returns true if argument value is mandatory.
98
+ # @return [Boolean]
86
99
  def mandatory?
87
100
  not optional?
88
101
  end
89
102
 
90
- # @todo
91
- def action
92
- @opts[:action]
93
- end
94
-
95
- # @todo
103
+ # Returns true if argument value is optional.
104
+ # @return [Boolean]
96
105
  def optional?
97
106
  @opts[:optional] == true
98
107
  end
99
108
 
100
- # @todo
109
+ # Returns parent Action instance that this Argument belongs to.
110
+ # @return [Saper::Action]
111
+ def action
112
+ @opts[:action]
113
+ end
114
+
115
+ # Returns String representation of argument's value.
116
+ # @return [String]
101
117
  def to_string
102
118
  value.to_s.inspect
103
119
  end