resulang 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-gemset +1 -1
- data/README.md +28 -59
- data/examples/my_resume/resume.yaml +29 -0
- data/examples/my_resume/templates/_other.html.erb +6 -0
- data/examples/my_resume/templates/resume.html.erb +1 -1
- data/lib/resulang.rb +0 -2
- data/lib/resulang/app.rb +2 -2
- data/lib/resulang/exec.rb +21 -13
- data/lib/resulang/resume.rb +8 -13
- data/lib/resulang/section.rb +33 -6
- data/lib/resulang/version.rb +1 -1
- data/resulang.gemspec +5 -4
- metadata +19 -7
- data/examples/my_resume/resume.html +0 -27
- data/examples/my_resume/resume.rb +0 -67
- data/lib/resulang/dsl.rb +0 -32
- data/lib/resulang/fields.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 793e6930ec9d8dabd66b436ed63916b1e18ee3b0fcfaa1adce684a8bdb019119
|
4
|
+
data.tar.gz: 6c28b6a08207b1a37e4ba1d071cf0e05f616b7621c6712545b1ab8d95912a1b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b43376f525f24a8f9d48cc15442b6f4c241a2202b4f712a1de8ad8e20e899c091de0bea20047b89871ae68e18996613e93189db2bb206b0950eaeb3bb6880dc2
|
7
|
+
data.tar.gz: 484df2a62449d87f4fa93056af0ea61c5d889bb4b73b09d68d29d650e3c36a8cd8057771d6c6a539b6c466e206afbbd8499acb1756c29f3202b67cb39cfb2100
|
data/.ruby-gemset
CHANGED
@@ -1 +1 @@
|
|
1
|
-
resulang
|
1
|
+
resulang
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Resulang
|
2
2
|
|
3
|
-
Resulang is a simple
|
3
|
+
Resulang is a simple tool for creating html resumes. It can also be used to
|
4
4
|
create other kinds of documents with structured data. It works by separating
|
5
5
|
the data from the html template, which means the data could theoretically be
|
6
6
|
used to generate other kinds of output in the future, not just html.
|
@@ -15,47 +15,41 @@ used to generate other kinds of output in the future, not just html.
|
|
15
15
|
|
16
16
|
Once resulang is installed, create a new resulang app with:
|
17
17
|
```sh
|
18
|
-
resulang new my_resume
|
18
|
+
bundle exec resulang new my_resume --section one two three
|
19
19
|
```
|
20
20
|
|
21
21
|
This will generate the basic structure of a resulang app as well as a few key files:
|
22
22
|
|
23
|
-
* `my_resume/data/resume.
|
23
|
+
* `my_resume/data/resume.yaml`
|
24
24
|
|
25
25
|
This is where you define your resume.
|
26
26
|
|
27
27
|
* `my_resume/templates/resume.html.erb`
|
28
28
|
|
29
29
|
This is where you write your resume html which has access to the data in
|
30
|
-
my_resume/data/resume.
|
30
|
+
my_resume/data/resume.yaml
|
31
31
|
|
32
32
|
|
33
33
|
A resume is broken into named sections. For example:
|
34
|
-
```
|
35
|
-
personal
|
36
|
-
name
|
37
|
-
phone
|
38
|
-
email
|
39
|
-
github
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
description <<-DESCRIPTION
|
34
|
+
```yaml
|
35
|
+
personal:
|
36
|
+
name: Peter Brindisi
|
37
|
+
phone: 555-555-5555
|
38
|
+
email: superduperprivate@example.com
|
39
|
+
github: https://github.com/npj
|
40
|
+
|
41
|
+
background:
|
42
|
+
description: >-
|
44
43
|
I am a guy that does things. Things are awesome and they are also cool.
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
point 'Reading about Haskell'
|
55
|
-
point 'Evangelizing monads'
|
56
|
-
point 'Making beer'
|
57
|
-
end
|
58
|
-
end
|
44
|
+
|
45
|
+
skills:
|
46
|
+
things: ['foo', 'bar', 'baz', 'qux']
|
47
|
+
|
48
|
+
hobbies:
|
49
|
+
points:
|
50
|
+
- Reading about Haskell
|
51
|
+
- Evangelizing monads
|
52
|
+
- Making beer
|
59
53
|
```
|
60
54
|
|
61
55
|
A template for the above data might look like this:
|
@@ -63,8 +57,8 @@ A template for the above data might look like this:
|
|
63
57
|
```html
|
64
58
|
<html>
|
65
59
|
<head>
|
66
|
-
<title><%= sections
|
67
|
-
<link rel="stylesheet" href="
|
60
|
+
<title><%= sections.personal.name %></title>
|
61
|
+
<link rel="stylesheet" href="css/style.css" />
|
68
62
|
</head>
|
69
63
|
<body>
|
70
64
|
<div class="section">
|
@@ -99,52 +93,27 @@ and "hobbies" sections might look like:
|
|
99
93
|
```html
|
100
94
|
<!-- my_resume/templates/_hobbies.html.erb -->
|
101
95
|
<ul>
|
102
|
-
<%
|
96
|
+
<% points.each do |point| %>
|
103
97
|
<li><%= point %></li>
|
104
98
|
<% end %>
|
105
99
|
</ul>
|
106
100
|
```
|
107
101
|
|
108
|
-
The data in `resume.rb` needs to be defined, which is what the
|
109
|
-
`my_resume/data/sections` directory is for. Each section is a class that
|
110
|
-
inherits from `Resulang::Section`. A section class declares the fields a
|
111
|
-
section can have as well as their types. The `Personal` and `Hobbies` sections
|
112
|
-
would look like this:
|
113
|
-
|
114
|
-
```ruby
|
115
|
-
# my_resume/data/sections/personal.rb
|
116
|
-
class Personal < Resulang::Section
|
117
|
-
string :name, :phone
|
118
|
-
email :email
|
119
|
-
link :github
|
120
|
-
end
|
121
|
-
```
|
122
|
-
|
123
|
-
```ruby
|
124
|
-
# my_resume/data/sections/hobbies.rb
|
125
|
-
class Hobbies < Resulang::Section
|
126
|
-
pointlist :info
|
127
|
-
end
|
128
|
-
```
|
129
|
-
|
130
102
|
To easily view changes to the resume as you make them, you can run a local
|
131
103
|
server with:
|
132
104
|
```sh
|
133
|
-
resulang server
|
105
|
+
bundle exec resulang server
|
134
106
|
```
|
135
107
|
|
136
|
-
However, if you make any changes to the classes in `my_resume/data/sections`
|
137
|
-
you must restart the server.
|
138
|
-
|
139
108
|
You can put assets like images and stylesheets in directories off `my_resume`,
|
140
109
|
like `css` and `images` or `assets/css` and `assets/images`. These can be
|
141
110
|
referenced in `resume.html.erb`.
|
142
111
|
|
143
112
|
To generate a static html page, run:
|
144
113
|
```sh
|
145
|
-
resulang make
|
114
|
+
bundle exec resulang make
|
146
115
|
```
|
147
116
|
|
148
117
|
This will output `./resume.html`
|
149
118
|
|
150
|
-
Please see the `
|
119
|
+
Please see the `examples` directory of this project for a working example.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
personal:
|
2
|
+
name: Peter Brindisi
|
3
|
+
phone: 555-555-5555
|
4
|
+
email: superduperprivate@example.com
|
5
|
+
github: https://github.com/npj
|
6
|
+
|
7
|
+
background:
|
8
|
+
description: >-
|
9
|
+
I am a guy that does things. Things are awesome and they are also cool.
|
10
|
+
|
11
|
+
skills:
|
12
|
+
things: ['foo', 'bar', 'baz', 'qux']
|
13
|
+
|
14
|
+
hobbies:
|
15
|
+
points:
|
16
|
+
- Reading about Haskell
|
17
|
+
- Evangelizing monads
|
18
|
+
- Making beer
|
19
|
+
|
20
|
+
other:
|
21
|
+
things:
|
22
|
+
- name: foo
|
23
|
+
description: foo desc
|
24
|
+
|
25
|
+
- name: bar
|
26
|
+
description: bar desc
|
27
|
+
|
28
|
+
- name: baz
|
29
|
+
description: baz desc
|
data/lib/resulang.rb
CHANGED
data/lib/resulang/app.rb
CHANGED
@@ -52,11 +52,11 @@ module Resulang
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def load_resume
|
55
|
-
@resume = Resulang::
|
55
|
+
@resume = Resulang::Resume.new(path: resume_path)
|
56
56
|
end
|
57
57
|
|
58
58
|
def resume_path
|
59
|
-
File.join(path, 'resume.
|
59
|
+
File.join(path, 'resume.yaml')
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
data/lib/resulang/exec.rb
CHANGED
@@ -17,28 +17,36 @@ module Resulang
|
|
17
17
|
contents.join("\n")
|
18
18
|
end
|
19
19
|
|
20
|
-
create_file('resume.
|
21
|
-
|
22
|
-
list.push("
|
23
|
-
end
|
24
|
-
|
25
|
-
sections = options[:sections].inject([]) do |list, s|
|
26
|
-
list.push("#{s} do\n\n end")
|
27
|
-
end
|
28
|
-
|
29
|
-
structure = "structure do\n " + declarations.join(" \n\n ") + "\nend"
|
30
|
-
data = "data do\n " + sections.join(" \n\n ") + "\nend"
|
20
|
+
create_file('resume.yaml') do
|
21
|
+
options[:sections].inject([]) do |list, s|
|
22
|
+
list.push("#{s}:")
|
23
|
+
end.join("\n\n")
|
24
|
+
end
|
31
25
|
|
32
|
-
|
26
|
+
empty_directory 'css'
|
27
|
+
inside('css') do
|
28
|
+
create_file('style.css')
|
33
29
|
end
|
34
30
|
|
35
31
|
empty_directory 'templates'
|
36
32
|
inside('templates') do
|
37
|
-
create_file('resume.html.erb')
|
33
|
+
create_file('resume.html.erb') do
|
34
|
+
<<-HTML
|
35
|
+
<html>
|
36
|
+
<head>
|
37
|
+
<link rel="stylesheet" href="css/style.css" />
|
38
|
+
</head>
|
39
|
+
<body>
|
40
|
+
#{options[:sections].map { |section| %Q{<div class="section"><%= render_section(:#{section}) %></div>} }.join("\n ")}
|
41
|
+
</body>
|
42
|
+
</html>
|
43
|
+
HTML
|
44
|
+
end
|
38
45
|
options[:sections].each do |s|
|
39
46
|
create_file("_#{s}.html.erb")
|
40
47
|
end
|
41
48
|
end
|
49
|
+
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
data/lib/resulang/resume.rb
CHANGED
@@ -1,22 +1,17 @@
|
|
1
|
+
require 'psych'
|
2
|
+
|
1
3
|
module Resulang
|
2
4
|
class Resume
|
3
|
-
@@declared_sections = { }
|
4
|
-
|
5
5
|
attr_reader :sections
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@sections =
|
9
|
-
|
7
|
+
def initialize(path:)
|
8
|
+
@sections = OpenStruct.new
|
9
|
+
load_yaml(path)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
define_method(name) do |&instance_block|
|
16
|
-
unless @@declared_sections[name]
|
17
|
-
raise "Section \"#{name}\" not found"
|
18
|
-
end
|
19
|
-
@sections[name] = @@declared_sections[name].new(name: name, &instance_block)
|
12
|
+
private def load_yaml(path)
|
13
|
+
Psych.load_file(path).each do |section_name, section_data|
|
14
|
+
@sections[section_name] = Section.new(name: section_name, data: section_data)
|
20
15
|
end
|
21
16
|
end
|
22
17
|
end
|
data/lib/resulang/section.rb
CHANGED
@@ -1,17 +1,44 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
1
3
|
module Resulang
|
2
|
-
class Section
|
3
|
-
attr_reader :
|
4
|
+
class Section < OpenStruct
|
5
|
+
attr_reader :_section_name
|
4
6
|
|
5
|
-
include Fields
|
6
7
|
include Rendering
|
7
8
|
|
8
|
-
def initialize(name:,
|
9
|
-
|
10
|
-
|
9
|
+
def initialize(name:, data:)
|
10
|
+
super(_section_name: name)
|
11
|
+
interpret_object(self, data)
|
11
12
|
end
|
12
13
|
|
13
14
|
def get_binding
|
14
15
|
binding
|
15
16
|
end
|
17
|
+
|
18
|
+
private def interpret(value)
|
19
|
+
if (range = interpret_range(value))
|
20
|
+
range
|
21
|
+
elsif value.respond_to?(:keys)
|
22
|
+
interpret_object(OpenStruct.new, value)
|
23
|
+
elsif value.respond_to?(:map)
|
24
|
+
value.map { |v| interpret(v) }
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private def interpret_object(struct, value)
|
31
|
+
struct.tap do |s|
|
32
|
+
value.each do |key, value|
|
33
|
+
s[key] = interpret(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private def interpret_range(value)
|
39
|
+
if value.respond_to?(:keys) && value.keys == ['range']
|
40
|
+
(value['range'].first..value['range'].last)
|
41
|
+
end
|
42
|
+
end
|
16
43
|
end
|
17
44
|
end
|
data/lib/resulang/version.rb
CHANGED
data/resulang.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Resulang::VERSION
|
9
9
|
spec.authors = ["Peter Brindisi"]
|
10
10
|
spec.email = ["peter.brindisi+resulang@gmail.com"]
|
11
|
-
spec.summary = %q{Resulang is a simple
|
11
|
+
spec.summary = %q{Resulang is a simple tool to help create html resumes.}
|
12
12
|
spec.homepage = "https://github.com/npj/resulang"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
@@ -22,7 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency "rack", "~> 2.1.4"
|
23
23
|
spec.add_dependency "mime-types", "~> 3.0"
|
24
24
|
|
25
|
-
spec.add_development_dependency "bundler",
|
26
|
-
spec.add_development_dependency "rake",
|
27
|
-
spec.add_development_dependency "rspec",
|
25
|
+
spec.add_development_dependency "bundler", "~> 2.1.4"
|
26
|
+
spec.add_development_dependency "rake", "~> 12.3.3"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.4.0"
|
28
|
+
spec.add_development_dependency "pry", "~> 0.13.0"
|
28
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resulang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Brindisi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 3.4.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.13.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.13.0
|
111
125
|
description:
|
112
126
|
email:
|
113
127
|
- peter.brindisi+resulang@gmail.com
|
@@ -125,19 +139,17 @@ files:
|
|
125
139
|
- Rakefile
|
126
140
|
- bin/resulang
|
127
141
|
- examples/my_resume/assets/css/style.css
|
128
|
-
- examples/my_resume/resume.
|
129
|
-
- examples/my_resume/resume.rb
|
142
|
+
- examples/my_resume/resume.yaml
|
130
143
|
- examples/my_resume/server.ru
|
131
144
|
- examples/my_resume/templates/_background.html.erb
|
132
145
|
- examples/my_resume/templates/_hobbies.html.erb
|
146
|
+
- examples/my_resume/templates/_other.html.erb
|
133
147
|
- examples/my_resume/templates/_personal.html.erb
|
134
148
|
- examples/my_resume/templates/_skills.html.erb
|
135
149
|
- examples/my_resume/templates/resume.html.erb
|
136
150
|
- lib/resulang.rb
|
137
151
|
- lib/resulang/app.rb
|
138
|
-
- lib/resulang/dsl.rb
|
139
152
|
- lib/resulang/exec.rb
|
140
|
-
- lib/resulang/fields.rb
|
141
153
|
- lib/resulang/rendering.rb
|
142
154
|
- lib/resulang/resume.rb
|
143
155
|
- lib/resulang/section.rb
|
@@ -167,5 +179,5 @@ requirements: []
|
|
167
179
|
rubygems_version: 3.1.2
|
168
180
|
signing_key:
|
169
181
|
specification_version: 4
|
170
|
-
summary: Resulang is a simple
|
182
|
+
summary: Resulang is a simple tool to help create html resumes.
|
171
183
|
test_files: []
|
@@ -1,27 +0,0 @@
|
|
1
|
-
<html>
|
2
|
-
<head>
|
3
|
-
<title>Peter Brindisi</title>
|
4
|
-
<link rel="stylesheet" href="assets/css/style.css" />
|
5
|
-
</head>
|
6
|
-
<body>
|
7
|
-
<div class="section">
|
8
|
-
<div>Name: Peter Brindisi</div>
|
9
|
-
<div>Phone: 555-555-5555</div>
|
10
|
-
<div>Email: superduperprivate@example.com</div>
|
11
|
-
<div><a href="https://github.com/npj" target="_blank">https://github.com/npj</a></div>
|
12
|
-
</div>
|
13
|
-
<div class="section">
|
14
|
-
<div>I am a guy that does things. Things are awesome and they are also cool.</div>
|
15
|
-
</div>
|
16
|
-
<div class="section">
|
17
|
-
<div>foo bar baz qux</div>
|
18
|
-
</div>
|
19
|
-
<div class="section">
|
20
|
-
<ul>
|
21
|
-
<li>Reading about Haskell</li>
|
22
|
-
<li>Evangelizing monads</li>
|
23
|
-
<li>Making beer</li>
|
24
|
-
</ul>
|
25
|
-
</div>
|
26
|
-
</body>
|
27
|
-
</html>
|
@@ -1,67 +0,0 @@
|
|
1
|
-
structure do
|
2
|
-
section :personal do
|
3
|
-
string :name, :phone
|
4
|
-
email :email
|
5
|
-
link :github
|
6
|
-
end
|
7
|
-
|
8
|
-
section :background do
|
9
|
-
string :description
|
10
|
-
end
|
11
|
-
|
12
|
-
section :skills do
|
13
|
-
list :things
|
14
|
-
end
|
15
|
-
|
16
|
-
section :hobbies do
|
17
|
-
list :points
|
18
|
-
end
|
19
|
-
|
20
|
-
section :other do
|
21
|
-
list :things do
|
22
|
-
string :name, :description
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
data do
|
28
|
-
personal do
|
29
|
-
name 'Peter Brindisi'
|
30
|
-
phone '555-555-5555'
|
31
|
-
email 'superduperprivate@example.com'
|
32
|
-
github 'https://github.com/npj'
|
33
|
-
end
|
34
|
-
|
35
|
-
background do
|
36
|
-
description <<-DESCRIPTION
|
37
|
-
I am a guy that does things. Things are awesome and they are also cool.
|
38
|
-
DESCRIPTION
|
39
|
-
end
|
40
|
-
|
41
|
-
skills do
|
42
|
-
thing %{foo bar baz qux}
|
43
|
-
end
|
44
|
-
|
45
|
-
hobbies do
|
46
|
-
point 'Reading about Haskell'
|
47
|
-
point 'Evangelizing monads'
|
48
|
-
point 'Making beer'
|
49
|
-
end
|
50
|
-
|
51
|
-
other do
|
52
|
-
thing do
|
53
|
-
name 'foo'
|
54
|
-
description 'foo desc'
|
55
|
-
end
|
56
|
-
|
57
|
-
thing do
|
58
|
-
name 'bar'
|
59
|
-
description 'bar desc'
|
60
|
-
end
|
61
|
-
|
62
|
-
thing do
|
63
|
-
name 'baz'
|
64
|
-
description 'baz desc'
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/lib/resulang/dsl.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module Resulang
|
2
|
-
class Dsl
|
3
|
-
attr_reader :path, :resume
|
4
|
-
|
5
|
-
def initialize(path)
|
6
|
-
@resume = nil
|
7
|
-
@path = path
|
8
|
-
instance_eval(File.read(path))
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
# defines the sections and their typed fields
|
14
|
-
class Structure
|
15
|
-
def initialize(&block)
|
16
|
-
instance_eval(&block)
|
17
|
-
end
|
18
|
-
|
19
|
-
def section(name, &block)
|
20
|
-
Resume.declare_section!(name, &block)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def structure(&block)
|
25
|
-
Structure.new(&block)
|
26
|
-
end
|
27
|
-
|
28
|
-
def data(&block)
|
29
|
-
@resume = Resume.new(&block)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
data/lib/resulang/fields.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'active_support/inflector'
|
2
|
-
|
3
|
-
module Resulang
|
4
|
-
module Fields
|
5
|
-
def self.included(base)
|
6
|
-
base.extend(ClassMethods)
|
7
|
-
end
|
8
|
-
|
9
|
-
class Email < String
|
10
|
-
end
|
11
|
-
|
12
|
-
class Link < String
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
protected def string(*attrs)
|
17
|
-
fields(*attrs) { |value| value }
|
18
|
-
end
|
19
|
-
|
20
|
-
protected def email(*attrs)
|
21
|
-
fields(*attrs) { |value| Email.new(value) }
|
22
|
-
end
|
23
|
-
|
24
|
-
protected def link(*attrs)
|
25
|
-
fields(*attrs) { |value| Link.new(value) }
|
26
|
-
end
|
27
|
-
|
28
|
-
protected def list(*attrs, &item_decl)
|
29
|
-
attrs.each do |name|
|
30
|
-
define_method(name) do |*args, &block|
|
31
|
-
field_get(name)
|
32
|
-
end
|
33
|
-
|
34
|
-
singular = ActiveSupport::Inflector.singularize(name)
|
35
|
-
|
36
|
-
define_method(singular) do |*args, &item_def|
|
37
|
-
if args.empty? && item_def.nil?
|
38
|
-
raise "no arguments or definition block given for list #{singular}"
|
39
|
-
end
|
40
|
-
|
41
|
-
items = field_get(name) || []
|
42
|
-
|
43
|
-
if item_def.nil?
|
44
|
-
args.each { |a| items.push(a) }
|
45
|
-
elsif
|
46
|
-
items.push(Class.new(Section, &item_decl).new(name: name, &item_def))
|
47
|
-
end
|
48
|
-
|
49
|
-
field_set(name, items)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
protected def range(*attrs)
|
55
|
-
fields(*attrs) { |*values| (values.first..values.last) }
|
56
|
-
end
|
57
|
-
|
58
|
-
private def fields(*names, &block)
|
59
|
-
names.each do |name|
|
60
|
-
define_method(name) do |*args, &b|
|
61
|
-
if args.empty? && b.nil?
|
62
|
-
field_get(name)
|
63
|
-
else
|
64
|
-
field_set(name, block.call(*args, &b))
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
#
|
72
|
-
# Instance Methods
|
73
|
-
#
|
74
|
-
private def field_set(attr, value)
|
75
|
-
instance_variable_set("@#{attr}", value)
|
76
|
-
end
|
77
|
-
|
78
|
-
private def field_get(attr)
|
79
|
-
instance_variable_get("@#{attr}")
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|