lei 0.2.5 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88432e6baf81ba924cbd6854c36e7db67687bbae8868bc3d7ef0c20c8e61a396
4
- data.tar.gz: b91686862fef7821ba0eeb77535e8f6649a682fdaddd9b62abc4083bb23ea31c
3
+ metadata.gz: 000f325a9a0e5c76dbcdde0b1abc680d845ef5448f5626cb585d5e27038091e0
4
+ data.tar.gz: f0699fbe2e6145cf33e51b2eb0bc3e1e9bda7d8c3bd989a1fc1868b395888b02
5
5
  SHA512:
6
- metadata.gz: 8e42031363973f6bf6f9ac4f2899291616e87b716a85cd93931a2feb0b72294a9a465ae444f481660f4769adc46ee412221e5078a63d57e88fab62f4d3fa28b4
7
- data.tar.gz: 9eefaa9d7e99adcf60af755e4fa9dce2045143ff66a48e578407eb8f0d819d88b21cedb6622241c0fddfbb3bcba270b354412c41db517efaeafe8434ba8e81dd
6
+ metadata.gz: 93a6ee8f6f9bc41e7eceb7148c6c2039b652b8de30cc5e4a57f43c2e207e3fa6ca2f0e1c0cd3a960a01e5dd6602374ce4e1838503cc351f21b1e44dfc434f830
7
+ data.tar.gz: 852035dc81a85eeaa041dfeffe8d4b3b103765e8b14948ad4a68468011998ee21ba00c1a7a23ca1859e2a7756f5efc9092190c3657aa9898e879a9ae436b11dc
@@ -44,25 +44,6 @@ content = <<~CONTENT
44
44
  }
45
45
  end
46
46
 
47
- get "/filter" do
48
- content = ContentHelpers.get_content(settings.content_dir)
49
-
50
- ContentHelpers.filter_content(content, params)
51
- redirect 404 if content.length == 0
52
-
53
- url = request.url
54
-
55
- ContentHelpers.time_sort(content)
56
- contentParts = ContentHelpers.paginate(content, params, url)
57
-
58
- slim :search_results, locals: {
59
- **contentParts,
60
- style: ContentHelpers.load_css(settings.stylesheet),
61
- title: "Filtered Results",
62
- url: url
63
- }
64
- end
65
-
66
47
  not_found do
67
48
  slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
68
49
  end
@@ -106,11 +87,62 @@ custom = <<~CUSTOM
106
87
  end
107
88
  CUSTOM
108
89
 
90
+ search = <<~SEARCH
91
+ puts "\\tController: Search"
92
+
93
+ class SearchController < Sinatra::Base
94
+
95
+ set :content_dir, "\#{$root}/{\#{ContentHelpers.get_content_dirs.join(",")}}"
96
+ set :stylesheet, "search"
97
+ set :public_folder, $assets_root
98
+ set :views, $views
99
+
100
+ get "/" do
101
+ url = request.url
102
+
103
+ slim :search, locals: {
104
+ style: ContentHelpers.load_css(settings.stylesheet),
105
+ title: "Search",
106
+ url: url
107
+ }
108
+ end
109
+
110
+ post "/query" do
111
+ redirect ContentHelpers.get_searchdest(params)
112
+ end
113
+
114
+ get "/results" do
115
+ content = ContentHelpers.get_content(settings.content_dir)
116
+
117
+ ContentHelpers.filter_content(content, params)
118
+ redirect 404 if content.length == 0
119
+
120
+ url = request.url
121
+
122
+ ContentHelpers.time_sort(content)
123
+ contentParts = ContentHelpers.paginate(content, params, url)
124
+
125
+ slim :search_results, locals: {
126
+ **contentParts,
127
+ style: ContentHelpers.load_css("\#{settings.stylesheet}_results"),
128
+ title: "Filtered Results",
129
+ url: url
130
+ }
131
+ end
132
+
133
+ not_found do
134
+ slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
135
+ end
136
+
137
+ end
138
+ SEARCH
139
+
109
140
  files = {
110
141
  "content.rb": content,
111
- "custom.rb": custom
142
+ "custom.rb": custom,
143
+ "search.rb": search
112
144
  }
113
145
 
114
146
  loc = "$(pwd)/controllers"
115
147
 
116
- makeFiles(files, loc)
148
+ makeFiles(files, loc)
data/bin/_app/_helpers.rb CHANGED
@@ -46,6 +46,10 @@ content = <<~CONTENT
46
46
  all - classified
47
47
  end
48
48
 
49
+ def self.get_content_dirs
50
+ YAML.load_file($contentDirs)
51
+ end
52
+
49
53
  def self.get_post(contentDir, title)
50
54
  content = self.get_content(contentDir)
51
55
 
@@ -54,6 +58,35 @@ content = <<~CONTENT
54
58
  content.include?(post) ? [ post ] : []
55
59
  end
56
60
 
61
+ def self.get_searchdest(params)
62
+ parts = {}
63
+
64
+ term = params["term"]
65
+
66
+ parts["term"] = self.sanitize_term(term) if !term.nil? && term != ""
67
+
68
+ whenp = params["when"]
69
+ specificity = params["specificity"]
70
+
71
+ if !whenp.nil? && whenp != "" && !specificity.nil? && specificity != ""
72
+ begin
73
+ whenRange = Date.parse(whenp)
74
+ year = "year=\#{whenRange.strftime("%Y")}"
75
+ month = "month=\#{whenRange.strftime("%m")}"
76
+ day = "day=\#{whenRange.strftime("%d")}"
77
+
78
+ parts["year"] = year if specificity.match?(/^(year|month|day)$/)
79
+ parts["month"] = month if specificity.match?(/^(month|day)$/)
80
+ parts["day"] = day if specificity == "day"
81
+ rescue => exception
82
+ \# TODO: Implement exception handling.
83
+ \# This block just serves to swallow the exception.
84
+ end
85
+ end
86
+
87
+ return self.mp_eu("search/results", parts, {})
88
+ end
89
+
57
90
  <<~load_css
58
91
  This function reads and returns the contents of a CSS file as a string.
59
92
  Its return value gets stored in a variable for ease of interpolation in
@@ -64,6 +97,7 @@ content = <<~CONTENT
64
97
  `cat \#{$style_root}/\#{filename}.css`
65
98
  end
66
99
 
100
+ \# Merge Params, Encode URL.
67
101
  def self.mp_eu(path, params, replacement)
68
102
  newParams = {}
69
103
  params.each { |k, v| newParams[k] = v }
@@ -125,6 +159,15 @@ content = <<~CONTENT
125
159
  CARPET.render(content)
126
160
  end
127
161
  end
162
+
163
+ def self.sanitize_term(path)
164
+ bannedChars = YAML.load_file($bannedChars)
165
+
166
+ processed = path
167
+ bannedChars.each { |char| processed = path.gsub(char, "") }
168
+
169
+ return processed
170
+ end
128
171
 
129
172
  def self.time_sort(content)
130
173
  content.sort_by! { |c| File::Stat.new(c).mtime }
@@ -153,6 +196,8 @@ module GlobalUtils
153
196
  $views = "\#{$root}/views"
154
197
 
155
198
  $banlist = "\#{$root}/banlist.yml"
199
+ $contentDirs = "\#{$root}/contentlist.yml"
200
+ $bannedChars = "\#{$root}/illegalchars.yml"
156
201
 
157
202
  <<~AMP
158
203
  AMP Static Header Parts, as of 15 APR 2018:
@@ -177,7 +222,19 @@ module GlobalUtils
177
222
 
178
223
  $amp_bind = "<script async custom-element=\\"amp-bind\\" src=\\"https://cdn.ampproject.org/v0/amp-bind-0.1.js\\"></script>"
179
224
  end
180
-
225
+
226
+ def self.assemble_query(params)
227
+ return "" if params.nil? || params.length == 0
228
+
229
+ queryString = ""
230
+ params.each_index do |idx|
231
+ sym = idx == 0 ? "?" : "&"
232
+ queryString += "\#{sym}\#{params[idx]}"
233
+ end
234
+
235
+ return queryString
236
+ end
237
+
181
238
  end
182
239
  GLOBAL
183
240
 
@@ -188,4 +245,4 @@ files = {
188
245
 
189
246
  loc = "$(pwd)/helpers"
190
247
 
191
- makeFiles(files, loc)
248
+ makeFiles(files, loc)
data/bin/_app/_root.rb CHANGED
@@ -51,6 +51,13 @@ config = <<~CONFIG
51
51
  end
52
52
  CONFIG
53
53
 
54
+ contentlist = <<~CONTENTLIST
55
+ ---
56
+ - content
57
+ - welcome
58
+ ...
59
+ CONTENTLIST
60
+
54
61
  controllerlist = <<~CONTROLLERLIST
55
62
  ---
56
63
  -
@@ -61,6 +68,10 @@ controllerlist = <<~CONTROLLERLIST
61
68
  file: content
62
69
  name: ContentController
63
70
  path: /content
71
+ -
72
+ file: search
73
+ name: SearchController
74
+ path: /search
64
75
  ...
65
76
  CONTROLLERLIST
66
77
 
@@ -76,15 +87,19 @@ customlist = <<~CUSTOMLIST
76
87
  CUSTOMLIST
77
88
 
78
89
  dockerfile = <<~DOCKERFILE
79
- FROM starefossen/ruby-node:2-10-alpine
90
+ FROM starefossen/ruby-node:2-10
91
+
92
+ RUN gem install lei
93
+
94
+ WORKDIR /Users/EMC3/Projects/test
80
95
 
81
- WORKDIR #{`pwd`}
82
96
  COPY . .
83
97
 
84
- RUN gem install bundler
85
- RUN gem install lei
98
+ RUN bundle install
99
+
100
+ EXPOSE 80
86
101
 
87
- CMD [ "lei", "install_deps" ]
102
+ CMD puma -b tcp://0.0.0.0:80
88
103
  DOCKERFILE
89
104
 
90
105
  gems = <<~GEMS
@@ -123,7 +138,9 @@ gulp = <<~GULP
123
138
  gulp.dest(cssDest)
124
139
  ],
125
140
  function(err) {
126
- console.log("--- err:", err);
141
+ if (err) {
142
+ console.log("--- err:", err);
143
+ }
127
144
  }
128
145
  );
129
146
  }
@@ -156,10 +173,17 @@ ignore = <<~IGNORE
156
173
  # *.md
157
174
  IGNORE
158
175
 
176
+ illegalchars = <<~ILLEGALCHARS
177
+ ---
178
+ - "."
179
+ - "/"
180
+ ...
181
+ ILLEGALCHARS
182
+
159
183
  launch = <<~LAUNCH
160
- #!/bin/bash
184
+ \#!/bin/bash
161
185
 
162
- # Provide port number as argument.
186
+ \# Provide port number as argument.
163
187
  puma -b tcp://0.0.0.0:$1
164
188
  LAUNCH
165
189
 
@@ -200,13 +224,15 @@ files = {
200
224
  ".gitignore": ignore,
201
225
  "banlist.yml": banlist,
202
226
  "config.ru": config,
227
+ "contentlist.yml": contentlist,
203
228
  "controllerlist.yml": controllerlist,
204
229
  "customlist.yml": customlist,
205
230
  "Dockerfile": dockerfile,
206
231
  "Gemfile": gems,
207
232
  "gulpfile.js": gulp,
233
+ "illegalchars.yml": illegalchars,
208
234
  "launch.sh": launch,
209
235
  "package.json": package
210
236
  }
211
237
 
212
- makeFiles(files, loc)
238
+ makeFiles(files, loc)
data/bin/_app/_src.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  require_relative "../functions"
2
2
 
3
3
  common = <<~COMMON
4
+ @anim-bg-color: {
5
+ transition: background-color 0.35s, color 0.35s;
6
+ };
7
+
4
8
  @center-vert: {
5
9
  display: flex;
6
10
  flex-direction: column;
@@ -24,11 +28,47 @@ common = <<~COMMON
24
28
  font-weight: 300;
25
29
  };
26
30
 
31
+ @full-bar-dark: {
32
+ background-color: rgba(0, 0, 0, 0.9);
33
+ box-sizing: border-box;
34
+ color: white;
35
+ width: 100vw;
36
+ };
37
+
38
+ @full-bar-light: {
39
+ background-color: rgba(0, 0, 0, 0.1);
40
+ box-sizing: border-box;
41
+ width: 100vw;
42
+ };
43
+
27
44
  @full-page: {
45
+ font-size: 14px;
28
46
  width: 100vw;
29
47
  min-height: 100vh;
30
48
  };
31
49
 
50
+ @link-content: {
51
+ color: black;
52
+ font-weight: bold;
53
+ };
54
+
55
+ @link-ad: {
56
+ color: white;
57
+ text-decoration: none;
58
+ };
59
+
60
+ @link-al: {
61
+ color: black;
62
+ text-decoration: none;
63
+ };
64
+
65
+ @spread-vert: {
66
+ display: flex;
67
+ flex-direction: column;
68
+ justify-content: space-between;
69
+ align-items: center;
70
+ };
71
+
32
72
  @std-content: {
33
73
  max-width: 50em;
34
74
  width: 80vw;
@@ -44,7 +84,7 @@ common = <<~COMMON
44
84
 
45
85
  .base-page {
46
86
  -webkit-tap-highlight-color: transparent;
47
- font-family: "Lato", sans-serif;
87
+ font-family: 'Lato', sans-serif;
48
88
  background-color: rgb(240, 240, 240);
49
89
  @std-margin();
50
90
 
@@ -66,11 +106,61 @@ common = <<~COMMON
66
106
  .space-to-left {
67
107
  padding-left: 1em;
68
108
  }
69
-
109
+
70
110
  .space-to-right {
71
111
  padding-right: 1em;
72
112
  }
73
113
  };
114
+
115
+ .main-icon {
116
+ @fs10();
117
+ padding: 0em;
118
+ }
119
+
120
+ .std-mp {
121
+ @std-margin();
122
+ @std-padding();
123
+ };
124
+
125
+ .page-nav-button {
126
+ padding: 0em;
127
+
128
+ a {
129
+ .std-mp;
130
+ @anim-bg-color();
131
+ @full-bar-light();
132
+ @link-al();
133
+ bottom: 0vh;
134
+ display: block;
135
+ text-align: center;
136
+ }
137
+
138
+ a:hover {
139
+ @anim-bg-color();
140
+ @full-bar-dark();
141
+ @link-ad();
142
+ }
143
+ }
144
+
145
+ .index-section {
146
+ @full-page();
147
+ @spread-vert();
148
+
149
+ p:nth-child(2) {
150
+ .main-icon;
151
+ }
152
+
153
+ p:last-child {
154
+ .page-nav-button;
155
+ }
156
+ }
157
+
158
+ .return-previous {
159
+ p:first-child {
160
+ .page-nav-button;
161
+ }
162
+ }
163
+
74
164
  COMMON
75
165
 
76
166
  content = <<~CONTENT
@@ -124,6 +214,72 @@ notfound = <<~NOTFOUND
124
214
  }
125
215
  NOTFOUND
126
216
 
217
+ search = <<~SEARCH
218
+ @import "_common";
219
+
220
+ html, body {
221
+ .base-page;
222
+ }
223
+
224
+ h1 {
225
+ @fw300();
226
+ }
227
+
228
+ #search {
229
+ @center-vert();
230
+ @full-page();
231
+
232
+ input, select {
233
+ border: 1px solid rgb(100, 100, 100);
234
+ border-radius: 0.2em;
235
+ display: block;
236
+ font-size: 1.6em;
237
+ margin-bottom: 1em;
238
+ padding: 0.4em;
239
+ }
240
+
241
+ input[type="submit"], select {
242
+ width: 100%;
243
+ }
244
+
245
+ input:focus, select:focus {
246
+ outline: none;
247
+ box-shadow: 0 0 0 0.05em rgba(0, 123, 255, .5);
248
+ }
249
+
250
+ select {
251
+ -webkit-appearance: none;
252
+ -moz-appearance: none;
253
+ appearance: none;
254
+ }
255
+ }
256
+ SEARCH
257
+
258
+ searchresults = <<~SEARCHRESULTS
259
+ @import "_common";
260
+
261
+ html, body {
262
+ .base-page;
263
+ }
264
+
265
+ h1 {
266
+ @fw300();
267
+ }
268
+
269
+ #results {
270
+ @center-vert();
271
+ @full-page();
272
+ }
273
+
274
+ .content {
275
+ padding-bottom: 8px;
276
+ padding-left: 24px;
277
+ padding-right: 24px;
278
+ padding-top: 24px;
279
+ @std-content();
280
+ }
281
+ SEARCHRESULTS
282
+
127
283
  welcome = <<~WELCOME
128
284
  @import "_common";
129
285
 
@@ -140,7 +296,7 @@ welcome = <<~WELCOME
140
296
  @fw300();
141
297
  text-align: center;
142
298
  }
143
-
299
+
144
300
  h2 {
145
301
  @fs2();
146
302
  @fw300();
@@ -162,9 +318,11 @@ files = {
162
318
  "_common.less": common,
163
319
  "content.less": content,
164
320
  "notfound.less": notfound,
321
+ "search.less": search,
322
+ "search_results.less": searchresults,
165
323
  "welcome.less": welcome
166
324
  }
167
325
 
168
326
  filesLoc = "#{dirLoc}/styles"
169
327
 
170
- makeFiles(files, filesLoc)
328
+ makeFiles(files, filesLoc)
data/bin/_app/_static.rb CHANGED
@@ -4,4 +4,4 @@ dirs = [ "styles" ]
4
4
 
5
5
  loc = "$(pwd)/static"
6
6
 
7
- makeDirs(dirs, loc)
7
+ makeDirs(dirs, loc)
data/bin/_app/_views.rb CHANGED
@@ -78,6 +78,38 @@ results = <<~RESULTS
78
78
  == post
79
79
  RESULTS
80
80
 
81
+ search = <<~SEARCH
82
+ doctype html
83
+ html[amp]
84
+ == slim :"global_partials/head",
85
+ locals: { title: title, style: style, url: url }
86
+ body
87
+ div#search
88
+ h1.content Search
89
+ form[action="/search/query" method="POST"]
90
+ input[
91
+ class="search-input"
92
+ name="term"
93
+ placeholder="Search term"
94
+ type="text"
95
+ ]
96
+ input[
97
+ class="search-input"
98
+ name="when"
99
+ type="date"
100
+ ]
101
+ select[name="specificity"]
102
+ option[value="" selected=true] (All time)
103
+ option[value="year"] Year
104
+ option[value="month"] Month
105
+ option[value="year"] Day
106
+ input[
107
+ class="search-input"
108
+ name="submit"
109
+ type="submit"
110
+ ]
111
+ SEARCH
112
+
81
113
  welcome = <<~WELCOME
82
114
  doctype html
83
115
  html[amp]
@@ -103,6 +135,7 @@ files = {
103
135
  "content.slim": content,
104
136
  "notfound.slim": notfound,
105
137
  "post.slim": post,
138
+ "search.slim": search,
106
139
  "search_results.slim": results,
107
140
  "welcome.slim": welcome
108
141
  }
@@ -119,4 +152,4 @@ contentFiles = { "pagination.slim": pagination }
119
152
 
120
153
  contentPartialsLoc = "#{dirLoc}/content_partials"
121
154
 
122
- makeFiles(contentFiles, contentPartialsLoc)
155
+ makeFiles(contentFiles, contentPartialsLoc)
data/bin/_app/_welcome.rb CHANGED
@@ -10,4 +10,4 @@ files = {
10
10
 
11
11
  loc = "$(pwd)/welcome"
12
12
 
13
- makeFiles(files, loc)
13
+ makeFiles(files, loc)
data/bin/_new/_content.rb CHANGED
@@ -25,9 +25,10 @@ def add_new(name)
25
25
  end
26
26
  CONTENT
27
27
 
28
- initialContent = "# #{capitalizedName}\nYour content goes here."
28
+ initialContent = "# #{capitalizedName}\n\nYour content goes here."
29
29
 
30
30
  cwd = Dir.pwd
31
+
31
32
  controllers = YAML.load_file("#{cwd}/controllerlist.yml")
32
33
  controllers.select! { |c| c["file"] != downcasedName }
33
34
 
@@ -37,8 +38,18 @@ def add_new(name)
37
38
  "path" => "/#{downcasedName}"
38
39
  }
39
40
 
41
+ controllers.sort! { |a, b| a["file"] <=> b["file"] }
42
+
43
+ content = YAML.load_file("#{cwd}/contentlist.yml")
44
+ content.select! { |c| c != downcasedName }
45
+
46
+ content << downcasedName
47
+
48
+ content.sort!
49
+
40
50
  `echo '#{controllers.to_yaml}' > #{cwd}/controllerlist.yml`
51
+ `echo '#{content.to_yaml}' > #{cwd}/contentlist.yml`
41
52
  `mkdir #{cwd}/#{downcasedName}`
42
53
  `echo '#{initialContent}' > #{cwd}/#{downcasedName}/#{downcasedName}.md`
43
54
  `echo '#{contentController}' > #{cwd}/controllers/#{downcasedName}.rb`
44
- end
55
+ end
data/bin/_new/_custom.rb CHANGED
@@ -10,6 +10,7 @@ def add_new(name)
10
10
  capitalizedName = name.capitalize
11
11
 
12
12
  cwd = Dir.pwd
13
+
13
14
  custom = YAML.load_file("#{cwd}/customlist.yml")
14
15
  custom.select! { |c| c["file"] != downcasedName }
15
16
 
@@ -20,6 +21,15 @@ def add_new(name)
20
21
  "content" => [ "#{downcasedName}.md" ]
21
22
  }
22
23
 
24
+ custom.sort! { |a, b| a["name"] <=> b["name"] }
25
+
26
+ content = YAML.load_file("#{cwd}/contentlist.yml")
27
+ content.select! { |c| c != downcasedName }
28
+
29
+ content << downcasedName
30
+
31
+ content.sort!
32
+
23
33
  customView = <<~VIEW
24
34
  doctype html
25
35
  html[amp]
@@ -60,12 +70,13 @@ def add_new(name)
60
70
  }
61
71
  STYLE
62
72
 
63
- initialContent = "# #{capitalizedName}\nYour content goes here."
73
+ initialContent = "# #{capitalizedName}\n\nYour content goes here."
64
74
 
65
75
  `echo '#{custom.to_yaml}' > #{cwd}/customlist.yml`
76
+ `echo '#{content.to_yaml}' > #{cwd}/contentlist.yml`
66
77
  `mkdir #{cwd}/#{downcasedName}`
67
78
  `echo '#{initialContent}' > #{cwd}/#{downcasedName}/#{downcasedName}.md`
68
79
  `echo '#{customView}' > #{cwd}/views/#{downcasedName}.slim`
69
80
  `echo '#{customStyle}' > #{cwd}/src/styles/#{downcasedName}.less`
70
81
  `gulp shrink`
71
- end
82
+ end
@@ -0,0 +1,15 @@
1
+ def dockerExists
2
+ versionStdout = `docker -v`
3
+
4
+ return versionStdout != nil && versionStdout != ""
5
+ end
6
+
7
+ def dockerNameArgIsValid(nameArg)
8
+ return nameArg != nil && nameArg != "" && nameArg.match(/^\w+$/)
9
+ end
10
+
11
+ def dockerVersionArgIsValid(versionArg)
12
+ return versionArg != nil &&
13
+ versionArg != "" &&
14
+ versionArg.match(/^[0-9]\.[0-9]\.[0-9]$/)
15
+ end
data/bin/functions.rb CHANGED
@@ -4,4 +4,4 @@ end
4
4
 
5
5
  def makeFiles(files, loc)
6
6
  files.each { |k, v| `touch #{loc}/#{k}; echo '#{v}' > #{loc}/#{k}` }
7
- end
7
+ end
data/bin/lei CHANGED
@@ -6,6 +6,7 @@ class Lei
6
6
  @validArg0 = [
7
7
  "content",
8
8
  "custom",
9
+ "docker_deploy",
9
10
  "help",
10
11
  "install",
11
12
  "install_deps"
@@ -15,22 +16,23 @@ class Lei
15
16
  def help
16
17
  puts <<~MAN
17
18
 
18
- Usage: lei @(content|custom|help|install) ?(ARG)
19
+ Usage: lei @(content|custom|help|install|install_deps|docker_deploy) ?(ARG) ?(ARG)
19
20
 
20
21
  `content`: Generates new serial, filterable content section with pagination. `ARG`: Content subject; should be camel-case!
21
22
  `custom`: Generates a single, new, custom page. `ARG`: Page subject.
22
23
  `help`: Get info about Lei and its commands.
23
24
  `install`: Generates a brand-new installation of Lei.
24
25
  `install_deps`: Installs dependencies only, for use with existing app.
26
+ `docker_deploy`: Builds Docker image based on Dockerfile and deploys image to your registry (requires Docker).
25
27
 
26
28
  MAN
27
29
  end
28
30
 
29
31
  def install
30
32
  require "#{@root}/_app/_root.rb"
31
-
33
+
32
34
  Dir.glob("#{@root}/_app/_*.rb").each { |f| require f }
33
-
35
+
34
36
  install_deps
35
37
  end
36
38
 
@@ -42,25 +44,55 @@ class Lei
42
44
  `chmod +x launch.sh`
43
45
  end
44
46
 
47
+ def docker_deploy
48
+ require "#{@root}/docker_utils"
49
+
50
+ if !dockerExists
51
+ puts "Docker does not exist; please install it before running this command."
52
+
53
+ return
54
+ end
55
+
56
+ arg1 = ARGV[1]
57
+ arg2 = ARGV[2]
58
+
59
+ if !dockerNameArgIsValid(arg1)
60
+ puts "Please supply project name (one word, alphanumeric only, _ allowed)."
61
+
62
+ return
63
+ end
64
+
65
+ if !dockerVersionArgIsValid(arg2)
66
+ puts "Invalid version format; please adhere to SemVer (Major.Minor.Patch)."
67
+
68
+ return
69
+ end
70
+
71
+ `docker build -t #{arg1}:#{arg2} .`
72
+ `docker push #{arg1}:#{arg2}`
73
+ end
74
+
45
75
  def go
46
76
  arg0 = ARGV[0]
47
-
77
+
48
78
  if !@validArg0.include?(arg0)
49
79
  puts "Invalid first argument: `#{arg0}`."
50
80
  puts "Use argument `help` to get info about Lei and its commands."
51
-
81
+
52
82
  return
53
83
  end
54
-
84
+
55
85
  case arg0
56
86
  when "install"
57
87
  install
88
+ when "install_deps"
89
+ install_deps
90
+ when "docker_deploy"
91
+ docker_deploy
58
92
  when "content", "custom"
59
93
  require "#{@root}/_new/_#{arg0}"
60
-
94
+
61
95
  add_new(ARGV[1])
62
- when "install_deps"
63
- install_deps
64
96
  when "help"
65
97
  help
66
98
  else
@@ -70,4 +102,4 @@ class Lei
70
102
  end
71
103
 
72
104
  lei = Lei.new
73
- lei.go
105
+ lei.go
@@ -1,7 +1,7 @@
1
1
  puts "\tController: Content"
2
2
 
3
3
  class ContentController < Sinatra::Base
4
-
4
+
5
5
  set :content_dir, "#{$root}/content"
6
6
  set :stylesheet, "content"
7
7
  set :public_folder, $assets_root
@@ -41,27 +41,8 @@ class ContentController < Sinatra::Base
41
41
  }
42
42
  end
43
43
 
44
- get "/filter" do
45
- content = ContentHelpers.get_content(settings.content_dir)
46
-
47
- ContentHelpers.filter_content(content, params)
48
- redirect 404 if content.length == 0
49
-
50
- url = request.url
51
-
52
- ContentHelpers.time_sort(content)
53
- contentParts = ContentHelpers.paginate(content, params, url)
54
-
55
- slim :search_results, locals: {
56
- **contentParts,
57
- style: ContentHelpers.load_css(settings.stylesheet),
58
- title: "Filtered Results",
59
- url: url
60
- }
61
- end
62
-
63
44
  not_found do
64
45
  slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
65
46
  end
66
47
 
67
- end
48
+ end
@@ -1,7 +1,7 @@
1
1
  puts "\tController: Custom"
2
2
 
3
3
  class CustomController < Sinatra::Base
4
-
4
+
5
5
  set :public_folder, $assets_root
6
6
  set :views, $views
7
7
 
@@ -30,4 +30,4 @@ class CustomController < Sinatra::Base
30
30
  slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
31
31
  end
32
32
 
33
- end
33
+ end
@@ -0,0 +1,47 @@
1
+ puts "\tController: Search"
2
+
3
+ class SearchController < Sinatra::Base
4
+
5
+ set :content_dir, "#{$root}/{#{ContentHelpers.get_content_dirs.join(",")}}"
6
+ set :stylesheet, "search"
7
+ set :public_folder, $assets_root
8
+ set :views, $views
9
+
10
+ get "/" do
11
+ url = request.url
12
+
13
+ slim :search, locals: {
14
+ style: ContentHelpers.load_css(settings.stylesheet),
15
+ title: "Search",
16
+ url: url
17
+ }
18
+ end
19
+
20
+ post "/query" do
21
+ redirect ContentHelpers.get_searchdest(params)
22
+ end
23
+
24
+ get "/results" do
25
+ content = ContentHelpers.get_content(settings.content_dir)
26
+
27
+ ContentHelpers.filter_content(content, params)
28
+ redirect 404 if content.length == 0
29
+
30
+ url = request.url
31
+
32
+ ContentHelpers.time_sort(content)
33
+ contentParts = ContentHelpers.paginate(content, params, url)
34
+
35
+ slim :search_results, locals: {
36
+ **contentParts,
37
+ style: ContentHelpers.load_css("#{settings.stylesheet}_results"),
38
+ title: "Filtered Results",
39
+ url: url
40
+ }
41
+ end
42
+
43
+ not_found do
44
+ slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
45
+ end
46
+
47
+ end
@@ -3,10 +3,10 @@ require "#{$root}/controllers/content"
3
3
  puts "\tController: Test"
4
4
 
5
5
  class TestController < ContentController
6
-
6
+
7
7
  set :content_dir, "#{$root}/test"
8
8
  set :stylesheet, "content"
9
9
  set :public_folder, $assets_root
10
10
  set :views, $views
11
11
 
12
- end
12
+ end
@@ -19,30 +19,34 @@ module ContentHelpers
19
19
  !post.match?(Regexp.new(term, true))
20
20
  end
21
21
  end
22
-
22
+
23
23
  yyyy = params["year"]
24
24
  if !yyyy.nil? && yyyy.length == 4
25
25
  content.reject! { |c| File::Stat.new(c).mtime.year != yyyy.to_i }
26
26
  end
27
-
27
+
28
28
  mm = params["month"]
29
29
  if !mm.nil? && mm.length == 2
30
30
  content.reject! { |c| File::Stat.new(c).mtime.month != mm.to_i }
31
31
  end
32
-
32
+
33
33
  dd = params["day"]
34
34
  if !dd.nil? && dd.length == 2
35
35
  content.reject! { |c| File::Stat.new(c).mtime.day != dd.to_i }
36
36
  end
37
37
  end
38
-
38
+
39
39
  def self.get_content(contentDir)
40
40
  all = Dir.glob("#{contentDir}/*.md")
41
41
  classified = YAML.load_file($banlist)
42
-
42
+
43
43
  all - classified
44
44
  end
45
45
 
46
+ def self.get_content_dirs
47
+ YAML.load_file($contentDirs)
48
+ end
49
+
46
50
  def self.get_post(contentDir, title)
47
51
  content = self.get_content(contentDir)
48
52
 
@@ -51,6 +55,35 @@ module ContentHelpers
51
55
  content.include?(post) ? [ post ] : []
52
56
  end
53
57
 
58
+ def self.get_searchdest(params)
59
+ parts = {}
60
+
61
+ term = params["term"]
62
+
63
+ parts["term"] = self.sanitize_term(term) if !term.nil? && term != ""
64
+
65
+ whenp = params["when"]
66
+ specificity = params["specificity"]
67
+
68
+ if !whenp.nil? && whenp != "" && !specificity.nil? && specificity != ""
69
+ begin
70
+ whenRange = Date.parse(whenp)
71
+ year = "year=#{whenRange.strftime("%Y")}"
72
+ month = "month=#{whenRange.strftime("%m")}"
73
+ day = "day=#{whenRange.strftime("%d")}"
74
+
75
+ parts["year"] = year if specificity.match?(/^(year|month|day)$/)
76
+ parts["month"] = month if specificity.match?(/^(month|day)$/)
77
+ parts["day"] = day if specificity == "day"
78
+ rescue => exception
79
+ # TODO: Implement exception handling.
80
+ # This block just serves to swallow the exception.
81
+ end
82
+ end
83
+
84
+ return self.mp_eu("search/results", parts, {})
85
+ end
86
+
54
87
  <<~load_css
55
88
  This function reads and returns the contents of a CSS file as a string.
56
89
  Its return value gets stored in a variable for ease of interpolation in
@@ -61,6 +94,7 @@ module ContentHelpers
61
94
  `cat #{$style_root}/#{filename}.css`
62
95
  end
63
96
 
97
+ # Merge Params, Encode URL.
64
98
  def self.mp_eu(path, params, replacement)
65
99
  newParams = {}
66
100
  params.each { |k, v| newParams[k] = v }
@@ -76,16 +110,16 @@ module ContentHelpers
76
110
  style: self.load_css("notfound")
77
111
  }
78
112
  end
79
-
113
+
80
114
  def self.paginate(content, params, url)
81
115
  pageParam = params["page"].to_i
82
-
116
+
83
117
  page = pageParam != 0 ? pageParam : 1
84
118
  pages = (content.length / 5.0).ceil
85
119
 
86
120
  firstIndex = (page - 1) * 5
87
121
  lastIndex = page * 5 - 1
88
-
122
+
89
123
  path = URI(url).path
90
124
  pageUrls = [ nil, nil, nil, nil ]
91
125
 
@@ -95,14 +129,14 @@ module ContentHelpers
95
129
  prev = (page - 1).to_s
96
130
  pageUrls[1] = self.mp_eu(path, params, { "page" => prev })
97
131
  end
98
-
132
+
99
133
  if page < pages
100
134
  foll = (page + 1).to_s
101
135
  pageUrls[2] = self.mp_eu(path, params, { "page" => foll })
102
136
 
103
137
  pageUrls[3] = self.mp_eu(path, params, { "page" => pages.to_s })
104
138
  end
105
-
139
+
106
140
  {
107
141
  content: self.parse_md(content[firstIndex..lastIndex]),
108
142
  page: page,
@@ -122,10 +156,19 @@ module ContentHelpers
122
156
  CARPET.render(content)
123
157
  end
124
158
  end
125
-
159
+
160
+ def self.sanitize_term(path)
161
+ bannedChars = YAML.load_file($bannedChars)
162
+
163
+ processed = path
164
+ bannedChars.each { |char| processed = path.gsub(char, "") }
165
+
166
+ return processed
167
+ end
168
+
126
169
  def self.time_sort(content)
127
170
  content.sort_by! { |c| File::Stat.new(c).mtime }
128
171
  content.reverse!
129
172
  end
130
173
 
131
- end
174
+ end
@@ -16,6 +16,8 @@ module GlobalUtils
16
16
  $views = "#{$root}/views"
17
17
 
18
18
  $banlist = "#{$root}/banlist.yml"
19
+ $contentDirs = "#{$root}/contentlist.yml"
20
+ $bannedChars = "#{$root}/illegalchars.yml"
19
21
 
20
22
  <<~AMP
21
23
  AMP Static Header Parts, as of 15 APR 2018:
@@ -40,5 +42,17 @@ module GlobalUtils
40
42
 
41
43
  $amp_bind = "<script async custom-element=\"amp-bind\" src=\"https://cdn.ampproject.org/v0/amp-bind-0.1.js\"></script>"
42
44
  end
43
-
44
- end
45
+
46
+ def self.assemble_query(params)
47
+ return "" if params.nil? || params.length == 0
48
+
49
+ queryString = ""
50
+ params.each_index do |idx|
51
+ sym = idx == 0 ? "?" : "&"
52
+ queryString += "#{sym}#{params[idx]}"
53
+ end
54
+
55
+ return queryString
56
+ end
57
+
58
+ end
@@ -97,4 +97,4 @@ RSpec.configure do |config|
97
97
  # as the one that triggered the failure.
98
98
  Kernel.srand config.seed
99
99
  =end
100
- end
100
+ end
@@ -12,28 +12,16 @@ RSpec.describe "Tests Module: ContentHelpers" do
12
12
  content = ContentHelpers.get_content(fixtures)
13
13
 
14
14
  it "Tests variable $banlist: Verifies exclusion" do
15
- expect(content.length).not_to eq 7
15
+ expect(content.length).to eq 6
16
16
  expect(content).not_to include "#{fixtures}/md-2.md"
17
17
  end
18
18
 
19
- it "Tests method time_sort: Correctly sorts by mtime" do
20
- ContentHelpers.time_sort(content)
21
-
22
- expect(content.first).to eq "#{fixtures}/md-1.md"
23
- expect(content.last).to eq "#{fixtures}/md-3.md"
24
- end
25
-
26
19
  just6 = []
27
20
  for i in 1..7
28
21
  just6 << "#{fixtures}/md-#{i}.md" if i != 2
29
22
  end
30
23
  ContentHelpers.time_sort(just6)
31
24
 
32
- it "Tests method get_content: Correctly retrieves content" do
33
- expect(content.length).to eq 6
34
- expect(content).to eq just6
35
- end
36
-
37
25
  it "Tests method get_post: Correctly retrieves post" do
38
26
  post = ContentHelpers.get_post(fixtures, "md-4")
39
27
  ContentHelpers.time_sort(post)
@@ -115,52 +103,6 @@ RSpec.describe "Tests Module: ContentHelpers" do
115
103
  expect(filtered[0]).to eq "#{fixtures}/md-3.md"
116
104
  end
117
105
 
118
- it "Tests method filter_content: Correctly filters on year" do
119
- params = { "year" => "2018" }
120
- filtered = just6.clone
121
- ContentHelpers.filter_content(filtered, params)
122
-
123
- expect(filtered.length).to eq 6
124
-
125
- params2 = { "year" => "2017" }
126
- ContentHelpers.filter_content(filtered, params2)
127
-
128
- expect(filtered.length).to eq 0
129
- end
130
-
131
- it "Tests method filter_content: Correctly filters on month" do
132
- params = { "year" => "2018", "month" => "05" }
133
- filtered = just6.clone
134
- ContentHelpers.filter_content(filtered, params)
135
-
136
- expect(filtered.length).to eq 6
137
-
138
- params2 = { "year" => "2018", "month" => "04" }
139
- ContentHelpers.filter_content(filtered, params2)
140
-
141
- expect(filtered.length).to eq 0
142
- end
143
-
144
- it "Tests method filter_content: Correctly filters on day" do
145
- params = { "year" => "2018", "month" => "05", "day" => "03" }
146
- filtered = just6.clone
147
- ContentHelpers.filter_content(filtered, params)
148
-
149
- expect(filtered.length).to eq 4
150
-
151
- params2 = { "year" => "2018", "month" => "05", "day" => "10" }
152
- filtered2 = just6.clone
153
- ContentHelpers.filter_content(filtered2, params2)
154
-
155
- expect(filtered2.length).to eq 1
156
-
157
- params3 = { "year" => "2018", "month" => "05", "day" => "04" }
158
- filtered3 = just6.clone
159
- ContentHelpers.filter_content(filtered3, params3)
160
-
161
- expect(filtered3.length).to eq 1
162
- end
163
-
164
106
  it "Tests method parse_md: Correctly generates HTML from Markdown" do
165
107
  converted = ContentHelpers.parse_md([ "#{fixtures}/md-1.md" ])
166
108
 
@@ -170,7 +112,7 @@ RSpec.describe "Tests Module: ContentHelpers" do
170
112
  it "Tests method load_css: Correctly returns CSS file contents" do
171
113
  processed = ContentHelpers.load_css("test")
172
114
 
173
- expect(processed).to eq ".mock{display: none;}"
115
+ expect(processed).to eq ".mock{display: none;}\n"
174
116
  end
175
117
 
176
- end
118
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lei
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Chang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-22 00:00:00.000000000 Z
11
+ date: 2021-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -57,10 +57,12 @@ files:
57
57
  - bin/_app/_welcome.rb
58
58
  - bin/_new/_content.rb
59
59
  - bin/_new/_custom.rb
60
+ - bin/docker_utils.rb
60
61
  - bin/functions.rb
61
62
  - bin/lei
62
63
  - example/controllers/content.rb
63
64
  - example/controllers/custom.rb
65
+ - example/controllers/search.rb
64
66
  - example/controllers/test.rb
65
67
  - example/helpers/content_helpers.rb
66
68
  - example/helpers/global_utils.rb
@@ -85,8 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
87
  - !ruby/object:Gem::Version
86
88
  version: '0'
87
89
  requirements: []
88
- rubyforge_project:
89
- rubygems_version: 2.7.6
90
+ rubygems_version: 3.1.2
90
91
  signing_key:
91
92
  specification_version: 4
92
93
  summary: A springboard for AMP-ready static sites