former 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +68 -0
- data/Rakefile +19 -0
- data/former.gemspec +21 -0
- data/lib/former/builder.rb +65 -0
- data/lib/former/element.rb +34 -0
- data/lib/former/ext.rb +10 -0
- data/lib/former/version.rb +3 -0
- data/lib/former.rb +4 -0
- data/test/builder_test.rb +31 -0
- metadata +115 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Brian Muller
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
= Former
|
2
|
+
|
3
|
+
Former turns an html string into a set of editable fields. For instance, if you want to give users the ability to edit certain parts of pregenerated HTML (like the href's of a's), this gem makes it easy to create the form and handle user input.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'former'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install former
|
18
|
+
|
19
|
+
== Usage
|
20
|
+
First, create a new parser that extends Builder class.
|
21
|
+
|
22
|
+
class Parser < Former::Builder
|
23
|
+
attr "a.important", :href
|
24
|
+
attr "img", :src
|
25
|
+
text "p", "a.important"
|
26
|
+
end
|
27
|
+
|
28
|
+
In this example, we want to be able to edit the location of all links that have a class of "important", the location of all images, and the text in any paragraphs or important links.
|
29
|
+
|
30
|
+
To produce the input fields from some example input HTML, first create an instance of your parser.
|
31
|
+
|
32
|
+
parsed = Parser.new "<p>some text<a class='important' href='http://alink.com'>some link text<img src='/an/image/path' /></a>last text</p>"
|
33
|
+
puts parsed.to_form_html
|
34
|
+
|
35
|
+
This will output:
|
36
|
+
|
37
|
+
<input name="former_0" type="text" value="some text" />
|
38
|
+
<input name="former_1" type="text" value="http://alink.com" />
|
39
|
+
<input name="former_2" type="text" value="some link text" />
|
40
|
+
<input name="former_3" type="text" value="/an/image/path" />
|
41
|
+
<input name="former_4" type="text" value="last text" />
|
42
|
+
|
43
|
+
You can then set fields individually or as a group (with, say, the params from a POST/GET):
|
44
|
+
|
45
|
+
parsed[0] = "A New Description"
|
46
|
+
parsed[1] = "http://anewlink.com"
|
47
|
+
# or...
|
48
|
+
parsed.set_values :former_0 => "A New Description", :former_1 => "http://anewlink.com"
|
49
|
+
|
50
|
+
When the new values have been set, you can spit out the new HTML version:
|
51
|
+
|
52
|
+
puts parsed.to_html
|
53
|
+
|
54
|
+
Will produce the original html with the new field values:
|
55
|
+
|
56
|
+
<p>A New Description<a class='important' href='http://anewlink.com'>some link...
|
57
|
+
|
58
|
+
By default, the fields created are input's. If you pass a block to the attr/text class methods, though, you can create your own.
|
59
|
+
|
60
|
+
class Parser < Former::Builder
|
61
|
+
attr "a.important", :href
|
62
|
+
attr("img", :src) { |elem, name|
|
63
|
+
# If the src url is a really long bit of text, you could do something like this.
|
64
|
+
# The name is the name (which has the index) necessary to set the value on a GET/POST
|
65
|
+
"<textarea name='#{name}'></textarea>"
|
66
|
+
}
|
67
|
+
text "p", "a.important"
|
68
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rdoc/task'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
task :default => [:test]
|
6
|
+
|
7
|
+
RDoc::Task.new("doc") { |rdoc|
|
8
|
+
rdoc.title = "Former - convert HTML to input forms for editable values"
|
9
|
+
rdoc.rdoc_dir = 'docs'
|
10
|
+
rdoc.rdoc_files.include('README.rdoc')
|
11
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
+
}
|
13
|
+
|
14
|
+
desc "Run all unit tests"
|
15
|
+
Rake::TestTask.new("test") { |t|
|
16
|
+
t.libs << "lib"
|
17
|
+
t.test_files = FileList['test/*.rb']
|
18
|
+
t.verbose = true
|
19
|
+
}
|
data/former.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'former/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "former"
|
7
|
+
gem.version = Former::VERSION
|
8
|
+
gem.authors = ["Brian Muller"]
|
9
|
+
gem.email = ["bamuller@gmail.com"]
|
10
|
+
gem.description = "Converts HTML to form fields for editing values in the HTML"
|
11
|
+
gem.summary = "Converts HTML to form fields for editing values in the HTML"
|
12
|
+
gem.homepage = "http://github.com/opbandit/former"
|
13
|
+
gem.files = `git ls-files`.split($/)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.add_dependency("actionpack", ">= 3.2.0")
|
18
|
+
gem.add_dependency("nokogiri", ">= 1.5.6")
|
19
|
+
gem.add_development_dependency("rake")
|
20
|
+
gem.add_development_dependency("rdoc")
|
21
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Former
|
4
|
+
class Builder
|
5
|
+
attr_reader :editable
|
6
|
+
|
7
|
+
def initialize(html)
|
8
|
+
@html = Nokogiri::HTML.parse(html)
|
9
|
+
|
10
|
+
matches = {}
|
11
|
+
@@queries.each { |path, qs|
|
12
|
+
@html.search(path).each { |node|
|
13
|
+
# if all we need is the text, only include text kids
|
14
|
+
if qs.length == 1 and qs.first[:query] == :text
|
15
|
+
node.traverse { |e| matches[e] = qs if e.text? and not matches.keys.include? e }
|
16
|
+
else
|
17
|
+
# otherwise, ignore just text requests
|
18
|
+
matches[node] = qs.select { |q| q[:query] != :text }
|
19
|
+
end
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
@editable = []
|
24
|
+
@html.traverse_prefix { |e|
|
25
|
+
(matches[e] || []).each { |query|
|
26
|
+
@editable << Element.new(e, query[:query], @editable.length, query[:block])
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def each(&block)
|
32
|
+
@editable.each { |e| block.call(e) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_form_html
|
36
|
+
@editable.map { |e| e.to_form_html }.join("\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_html
|
40
|
+
# nokogiri pads w/ xhtml/body elements
|
41
|
+
@html.search("//body").first.children.first.to_html
|
42
|
+
end
|
43
|
+
|
44
|
+
def []=(index, value)
|
45
|
+
@editable[index].set_value value
|
46
|
+
end
|
47
|
+
|
48
|
+
# vals should be { :former_0 => 'value', :former_1 => 'value two', ... }
|
49
|
+
def set_values(vals)
|
50
|
+
vals.each { |key, value|
|
51
|
+
self[key.to_s.split('_').last.to_i] = value
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.attr(elem, attr, &block)
|
56
|
+
@@queries ||= {}
|
57
|
+
@@queries[elem] ||= []
|
58
|
+
@@queries[elem] << { :query => attr, :block => block }
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.text(*elems, &block)
|
62
|
+
elems.each { |elem| attr(elem, :text, &block) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
|
3
|
+
module Former
|
4
|
+
class Element
|
5
|
+
include ActionView::Helpers::TagHelper
|
6
|
+
attr_reader :node, :query, :block
|
7
|
+
|
8
|
+
def initialize(node, query, index, block)
|
9
|
+
@node = node
|
10
|
+
@query = query
|
11
|
+
@block = block
|
12
|
+
@index = index
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_form_html
|
16
|
+
name = "former_#{@index}"
|
17
|
+
return @block.call(@node, name) unless @block.nil?
|
18
|
+
value = (@query == :text) ? @node.text : @node[@query]
|
19
|
+
tag(:input, :type => 'text', :name => name, :value => value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_value(value)
|
23
|
+
if @query == :text
|
24
|
+
@node.content = value
|
25
|
+
else
|
26
|
+
@node[@query] = value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_html
|
31
|
+
@node.to_html
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/former/ext.rb
ADDED
data/lib/former.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'former'
|
3
|
+
|
4
|
+
class Parser < Former::Builder
|
5
|
+
attr "a.important", :href
|
6
|
+
attr("img", :src)
|
7
|
+
text "p", "a.important"
|
8
|
+
end
|
9
|
+
|
10
|
+
class BuilderTest < Test::Unit::TestCase
|
11
|
+
def setup
|
12
|
+
@html_txt = '<p>some text<a class="important" href="http://alink.com">some link text<img src="/an/image/path"></a>last text</p>'
|
13
|
+
@parser = Parser.new @html_txt
|
14
|
+
puts @parser.to_form_html
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_parsing
|
18
|
+
assert_equal @parser.editable.length, 5
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_building
|
22
|
+
assert_equal @parser.to_html, @html_txt
|
23
|
+
new_html_txt = '<p>some new text<a class="important" href="http://alink.com">some link text<img src="/an/image/path"></a>last text</p>'
|
24
|
+
@parser[0] = "some new text"
|
25
|
+
assert_equal @parser.to_html, new_html_txt
|
26
|
+
|
27
|
+
# now set it back
|
28
|
+
@parser.set_values :former_0 => "some text"
|
29
|
+
@parser = Parser.new @html_txt
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: former
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brian Muller
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2013-02-19 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: actionpack
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.2.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: nokogiri
|
28
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.5.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
39
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rdoc
|
50
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *id004
|
59
|
+
description: Converts HTML to form fields for editing values in the HTML
|
60
|
+
email:
|
61
|
+
- bamuller@gmail.com
|
62
|
+
executables: []
|
63
|
+
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files: []
|
67
|
+
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- former.gemspec
|
75
|
+
- lib/former.rb
|
76
|
+
- lib/former/builder.rb
|
77
|
+
- lib/former/element.rb
|
78
|
+
- lib/former/ext.rb
|
79
|
+
- lib/former/version.rb
|
80
|
+
- test/builder_test.rb
|
81
|
+
homepage: http://github.com/opbandit/former
|
82
|
+
licenses: []
|
83
|
+
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: -2404963171909705179
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
hash: -2404963171909705179
|
104
|
+
segments:
|
105
|
+
- 0
|
106
|
+
version: "0"
|
107
|
+
requirements: []
|
108
|
+
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 1.8.24
|
111
|
+
signing_key:
|
112
|
+
specification_version: 3
|
113
|
+
summary: Converts HTML to form fields for editing values in the HTML
|
114
|
+
test_files:
|
115
|
+
- test/builder_test.rb
|