fragment 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +28 -0
- data/{MIT_LICENCE → MIT_LICENSE} +3 -2
- data/README.md +57 -35
- data/fragment.gemspec +13 -5
- data/lib/fragment.rb +9 -3
- data/lib/fragment/version.rb +7 -0
- data/spec/fragment_spec.rb +190 -0
- data/spec/spec_helper.rb +21 -0
- metadata +23 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 05b9ed2ebd1d81634b699810495aca5a66acb46e
|
4
|
+
data.tar.gz: 8d11babc8d25ade0f40112ec8c0c111cae637064
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a69a5f02a542d5acde4b37643a8cbf8cda4fbb5afe52b45468aebadb189b5d7e178c142dbb4c3628d39c7ff87f7dee3baf6b77a97a19aa76ebbca6a9a0bb8816
|
7
|
+
data.tar.gz: cf3b9dd2585853d1d4114874e304581838fe64423aa84144d771a3e808443663698f04f865bda30fac6a9166e96864f3898498645e497d2d8cf06790b9230d4c
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
fragment (1.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
specs:
|
8
|
+
diff-lcs (1.2.5)
|
9
|
+
rspec (3.2.0)
|
10
|
+
rspec-core (~> 3.2.0)
|
11
|
+
rspec-expectations (~> 3.2.0)
|
12
|
+
rspec-mocks (~> 3.2.0)
|
13
|
+
rspec-core (3.2.2)
|
14
|
+
rspec-support (~> 3.2.0)
|
15
|
+
rspec-expectations (3.2.0)
|
16
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
17
|
+
rspec-support (~> 3.2.0)
|
18
|
+
rspec-mocks (3.2.1)
|
19
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
20
|
+
rspec-support (~> 3.2.0)
|
21
|
+
rspec-support (3.2.2)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
fragment!
|
28
|
+
rspec
|
data/{MIT_LICENCE → MIT_LICENSE}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2011 Mickael Riga
|
1
|
+
Copyright (c) 2011-2015 Mickael Riga
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -16,4 +16,5 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
THE SOFTWARE.
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
data/README.md
CHANGED
@@ -9,49 +9,65 @@ In essence, Fragment works more or less like any builder.
|
|
9
9
|
|
10
10
|
First, how to install:
|
11
11
|
|
12
|
-
|
12
|
+
```
|
13
|
+
gem install fragment
|
14
|
+
```
|
15
|
+
|
16
|
+
Or in your `Gemfile`:
|
17
|
+
|
18
|
+
```
|
19
|
+
gem 'fragment'
|
20
|
+
```
|
13
21
|
|
14
22
|
Then you can require Fragment and use it that way:
|
15
23
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
write "\n<!-- This allows to write HTML directly when using a snippet -->\n"
|
32
|
-
write "\n<!-- like Google Analytics or including another fragment -->\n"
|
24
|
+
```
|
25
|
+
require 'fragment'
|
26
|
+
|
27
|
+
default = 'HTML'
|
28
|
+
|
29
|
+
html = Fragment.create do
|
30
|
+
doctype
|
31
|
+
html(:lang=>'en') do
|
32
|
+
head { title { "My Choice" } }
|
33
|
+
body do
|
34
|
+
comment "Here starts the body"
|
35
|
+
select(:name => 'language') do
|
36
|
+
['JS', 'HTML', 'CSS'].each do |l|
|
37
|
+
option(:value => l, :selected => l==default) { l }
|
33
38
|
end
|
34
39
|
end
|
35
|
-
|
40
|
+
write "\n<!-- This allows to write HTML directly when using a snippet -->\n"
|
41
|
+
write "\n<!-- like Google Analytics or including another fragment -->\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
36
46
|
|
37
47
|
If you try this example, you might notice a couple of things:
|
38
48
|
|
39
49
|
First of all, you have a `doctype` helper which only creates an HTML5 doctype.
|
40
|
-
If you want something else, you can use the `write` method which lets you
|
50
|
+
If you want something else, you can use the `write` method which lets you
|
51
|
+
write directly in place:
|
41
52
|
|
42
|
-
|
43
|
-
|
53
|
+
```
|
54
|
+
write "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN'"
|
55
|
+
write " 'http://www.w3.org/TR/html4/strict.dtd'>"
|
56
|
+
```
|
44
57
|
|
45
|
-
The major difference with Gestalt (if you used it) is that it does not accept
|
46
|
-
in the arguments. This simplifies the code a lot for a very small
|
47
|
-
So the argument is either a Hash that represents the attributes,
|
48
|
-
you would write in the HTML code.
|
58
|
+
The major difference with Gestalt (if you used it) is that it does not accept
|
59
|
+
content in the arguments. This simplifies the code a lot for a very small
|
60
|
+
sacrifice. So the argument is either a Hash that represents the attributes,
|
61
|
+
or a string like you would write in the HTML code.
|
49
62
|
|
50
|
-
One problem I had when creating fragments of HTML from code with a Hash for
|
51
|
-
is for attributes like
|
52
|
-
not have a negative value (not that I know of),
|
63
|
+
One problem I had when creating fragments of HTML from code with a Hash for
|
64
|
+
attributes is for attributes like `selected` or `checked` which are a bit
|
65
|
+
annoying because they do not have a negative value (not that I know of),
|
66
|
+
so you cannot write things like:
|
53
67
|
|
54
|
-
|
68
|
+
```
|
69
|
+
selected='not_selected'
|
70
|
+
```
|
55
71
|
|
56
72
|
I find this slightly irritating.
|
57
73
|
So what I did is that in the Hash, when a value is false, its key is removed.
|
@@ -59,11 +75,17 @@ This is what I did on the long example above for marking the default option.
|
|
59
75
|
|
60
76
|
Nothing fancy but quite good to be aware of.
|
61
77
|
|
62
|
-
If you
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
78
|
+
If you need more control on the scope of variables and basically stay in the
|
79
|
+
scope you are in, you can add an argument to the block which represents the
|
80
|
+
fragment itself. The change of arity changes the scope and since you are in the
|
81
|
+
current scope, every fragment method has to be called on the fragment object.
|
82
|
+
Here is an example which hopefully makes it clearer:
|
83
|
+
|
84
|
+
```
|
85
|
+
html = Fragment.create do |f|
|
86
|
+
f.h1 { "" }
|
87
|
+
end
|
88
|
+
```
|
67
89
|
|
68
90
|
Do not hesitate to fork the project if you want to help me improve it.
|
69
91
|
|
data/fragment.gemspec
CHANGED
@@ -1,13 +1,21 @@
|
|
1
|
+
require_relative './lib/fragment/version'
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
4
|
+
|
2
5
|
s.name = 'fragment'
|
3
|
-
s.version =
|
4
|
-
s.platform = Gem::Platform::RUBY
|
6
|
+
s.version = Fragment.version
|
5
7
|
s.summary = "Lightweight HTML builder"
|
6
8
|
s.description = "An HTML builder heavily based on Gestalt from the Ramaze framework. Its main purpose is to create fragments (hence the name), but is perfectly suited for building full pages."
|
7
|
-
s.files = `git ls-files`.split("\n").sort
|
8
|
-
s.require_path = './lib'
|
9
9
|
s.author = "Mickael Riga"
|
10
10
|
s.email = "mig@mypeplum.com"
|
11
11
|
s.homepage = "https://github.com/mig-hub/fragment"
|
12
|
-
s.
|
12
|
+
s.licenses = ['MIT']
|
13
|
+
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.require_path = './lib'
|
16
|
+
s.files = `git ls-files`.split("\n").sort
|
17
|
+
s.test_files = s.files.select { |p| p =~ /^spec\/.*_spec.rb/ }
|
18
|
+
|
19
|
+
s.add_development_dependency("rspec")
|
13
20
|
end
|
21
|
+
|
data/lib/fragment.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
|
+
require 'fragment/version'
|
2
|
+
|
1
3
|
class Fragment
|
2
4
|
attr_accessor :to_s
|
3
5
|
|
4
|
-
def self.create(&block); self.new(
|
5
|
-
|
6
|
+
def self.create(&block); self.new(&block).to_s; end
|
7
|
+
# create_here is kept for backward compatibility
|
8
|
+
def self.create_here(&block); self.new(&block).to_s; end
|
6
9
|
|
7
10
|
def initialize outer_scope=false, &block
|
11
|
+
# outer_scope argument is kept for backward compatibility
|
12
|
+
# but it is not used
|
13
|
+
# checking is simpler with arity instead
|
8
14
|
@to_s = ""
|
9
15
|
return self unless block_given?
|
10
|
-
|
16
|
+
if block.arity==0
|
11
17
|
instance_eval(&block)
|
12
18
|
else
|
13
19
|
block.call(self)
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "fragment"
|
3
|
+
|
4
|
+
RSpec.describe Fragment do
|
5
|
+
|
6
|
+
def fragment(&block); Fragment.create(&block); end
|
7
|
+
|
8
|
+
it "Builds simple tags" do
|
9
|
+
expect(fragment{ br }).to eq '<br />'
|
10
|
+
expect(fragment{ p }).to eq '<p />'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "Opens and closes tags" do
|
14
|
+
expect(fragment{ p{} }).to eq '<p></p>'
|
15
|
+
expect(fragment{ div{} }).to eq '<div></div>'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "Nests tags" do
|
19
|
+
expect(fragment{ p{ br } }).to eq '<p><br /></p>'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "Builds deeply nested tags" do
|
23
|
+
expect(fragment do
|
24
|
+
p do
|
25
|
+
div do
|
26
|
+
ol do
|
27
|
+
li
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end).to eq '<p><div><ol><li /></ol></div></p>'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "Builds deeply nested tags with repetition" do
|
35
|
+
expect(fragment do
|
36
|
+
p do
|
37
|
+
div do
|
38
|
+
ol do
|
39
|
+
li
|
40
|
+
li
|
41
|
+
end
|
42
|
+
ol do
|
43
|
+
li
|
44
|
+
li
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end).to eq '<p><div><ol><li /><li /></ol><ol><li /><li /></ol></div></p>'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "Builds deeply nested tags with strings" do
|
52
|
+
expect(fragment do
|
53
|
+
p do
|
54
|
+
div {'Hello, World'}
|
55
|
+
end
|
56
|
+
end).to eq '<p><div>Hello, World</div></p>'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "Allows to write directly if needed" do
|
60
|
+
expect(fragment do
|
61
|
+
write "<!DOCTYPE html>"
|
62
|
+
end).to eq '<!DOCTYPE html>'
|
63
|
+
end
|
64
|
+
|
65
|
+
it "Builds a full HTML page" do
|
66
|
+
expect(fragment do
|
67
|
+
doctype
|
68
|
+
html do
|
69
|
+
head do
|
70
|
+
title {"Hello World"}
|
71
|
+
end
|
72
|
+
body do
|
73
|
+
h1 {"Hello World"}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end).to eq "<!DOCTYPE html>\n<html><head><title>Hello World</title></head><body><h1>Hello World</h1></body></html>"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "Builds with some ruby inside" do
|
80
|
+
expect(fragment do
|
81
|
+
table do
|
82
|
+
tr do
|
83
|
+
%w[one two three].each do |s|
|
84
|
+
td{s}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end).to eq '<table><tr><td>one</td><td>two</td><td>three</td></tr></table>'
|
89
|
+
end
|
90
|
+
|
91
|
+
it "Builds escapeable attributes" do
|
92
|
+
expect(fragment {
|
93
|
+
a(:href => "http://example.org/?a=one&b=two") {
|
94
|
+
"Click here"
|
95
|
+
}
|
96
|
+
}).to eq "<a href='http://example.org/?a=one&b=two'>Click here</a>"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "Should accept attributes in a string" do
|
100
|
+
expect(fragment{ input("type='text'") }).to eq "<input type='text' />"
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'Should accept symbols as attributes' do
|
104
|
+
input = fragment{ input(:type => :text, :value => :one) }
|
105
|
+
|
106
|
+
expect(input).to match /type='text'/
|
107
|
+
expect(input).to match /value='one'/
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'Builds tags with prefix' do
|
111
|
+
expect(fragment{ tag "prefix:local" }).to eq '<prefix:local />'
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'Builds tags with a variety of characters' do
|
115
|
+
# with "-"
|
116
|
+
expect(fragment{ tag "hello-world" }).to eq '<hello-world />'
|
117
|
+
# with Hiragana
|
118
|
+
expect(fragment{ tag "あいうえお" }).to eq '<あいうえお />'
|
119
|
+
end
|
120
|
+
|
121
|
+
it "Has a practicle way to add attributes like 'selected' based on boolean" do
|
122
|
+
@selected = false
|
123
|
+
expect(fragment do
|
124
|
+
option({:name => 'opt', :selected => @selected})
|
125
|
+
option(:name => 'opt', :selected => !@selected)
|
126
|
+
option(:name => 'opt', :selected => @i_am_nil)
|
127
|
+
end).to eq "<option name='opt' /><option name='opt' selected='true' /><option name='opt' />"
|
128
|
+
end
|
129
|
+
|
130
|
+
it "Builds a more complex HTML page with a variable in the outer scope" do
|
131
|
+
|
132
|
+
default = 'HTML'
|
133
|
+
|
134
|
+
html = Fragment.new do
|
135
|
+
doctype
|
136
|
+
html(:lang=>'en') do
|
137
|
+
head { title { "My Choice" } }
|
138
|
+
body do
|
139
|
+
comment "Here starts the body"
|
140
|
+
select(:name => 'language') do
|
141
|
+
['JS', 'HTML', 'CSS'].each do |l|
|
142
|
+
option(:value => l, :selected => l==default) { l }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
write "\n<!-- This allows to write HTML directly when using a snippet -->\n"
|
146
|
+
write "\n<!-- like Google Analytics or including another fragment -->\n"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end.to_s
|
150
|
+
|
151
|
+
expect(html).to eq "<!DOCTYPE html>\n<html lang='en'><head><title>My Choice</title></head><body>\n<!-- Here starts the body -->\n<select name='language'><option value='JS'>JS</option><option value='HTML' selected='true'>HTML</option><option value='CSS'>CSS</option></select>\n<!-- This allows to write HTML directly when using a snippet -->\n\n<!-- like Google Analytics or including another fragment -->\n</body></html>"
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'Can be used inside the scope of an object' do
|
156
|
+
class Stranger
|
157
|
+
attr_accessor :name, :comment
|
158
|
+
def show_comment
|
159
|
+
Fragment.create do |b|
|
160
|
+
b.p{ self.comment }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
def show_summary
|
164
|
+
Fragment.create do |b|
|
165
|
+
b.article do
|
166
|
+
b.h1{ self.name }
|
167
|
+
b.p{ self.comment }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
def fail_summary
|
172
|
+
Fragment.create do
|
173
|
+
article do
|
174
|
+
h1{ self.name }
|
175
|
+
p{ self.comment }
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
s = Stranger.new
|
182
|
+
s.name = 'The Doors'
|
183
|
+
s.comment = 'Strange days'
|
184
|
+
expect(s.show_comment).to eq '<p>Strange days</p>'
|
185
|
+
expect(s.show_summary).to eq '<article><h1>The Doors</h1><p>Strange days</p></article>'
|
186
|
+
expect(s.fail_summary).to eq "<article><h1><name /></h1><p>\n<!-- -->\n</p></article>"
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
|
3
|
+
config.expect_with :rspec do |expectations|
|
4
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
5
|
+
end
|
6
|
+
config.mock_with :rspec do |mocks|
|
7
|
+
mocks.verify_partial_doubles = true
|
8
|
+
end
|
9
|
+
config.filter_run :focus
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.disable_monkey_patching!
|
12
|
+
config.warnings = true
|
13
|
+
if config.files_to_run.one?
|
14
|
+
config.default_formatter = 'doc'
|
15
|
+
end
|
16
|
+
config.profile_examples = 10
|
17
|
+
config.order = :random
|
18
|
+
Kernel.srand config.seed
|
19
|
+
|
20
|
+
end
|
21
|
+
|
metadata
CHANGED
@@ -1,32 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fragment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mickael Riga
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-07-01 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
14
|
+
name: rspec
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
26
|
+
version: '0'
|
30
27
|
description: An HTML builder heavily based on Gestalt from the Ramaze framework. Its
|
31
28
|
main purpose is to create fragments (hence the name), but is perfectly suited for
|
32
29
|
building full pages.
|
@@ -36,33 +33,40 @@ extensions: []
|
|
36
33
|
extra_rdoc_files: []
|
37
34
|
files:
|
38
35
|
- .gitignore
|
39
|
-
-
|
36
|
+
- .rspec
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- MIT_LICENSE
|
40
40
|
- README.md
|
41
41
|
- fragment.gemspec
|
42
42
|
- lib/fragment.rb
|
43
|
+
- lib/fragment/version.rb
|
44
|
+
- spec/fragment_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
43
46
|
- test/spec_fragment.rb
|
44
47
|
homepage: https://github.com/mig-hub/fragment
|
45
|
-
licenses:
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
46
51
|
post_install_message:
|
47
52
|
rdoc_options: []
|
48
53
|
require_paths:
|
49
54
|
- ./lib
|
50
55
|
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
56
|
requirements:
|
53
|
-
- -
|
57
|
+
- - '>='
|
54
58
|
- !ruby/object:Gem::Version
|
55
59
|
version: '0'
|
56
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
61
|
requirements:
|
59
|
-
- -
|
62
|
+
- - '>='
|
60
63
|
- !ruby/object:Gem::Version
|
61
64
|
version: '0'
|
62
65
|
requirements: []
|
63
66
|
rubyforge_project:
|
64
|
-
rubygems_version:
|
67
|
+
rubygems_version: 2.0.14
|
65
68
|
signing_key:
|
66
|
-
specification_version:
|
69
|
+
specification_version: 4
|
67
70
|
summary: Lightweight HTML builder
|
68
|
-
test_files:
|
71
|
+
test_files:
|
72
|
+
- spec/fragment_spec.rb
|