lisp-rails-view 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dbdddd6688a527855ed9e36b3219ae465820bbaa
4
+ data.tar.gz: 09f2e4529a22af4ebccd5e28e8b6269a2b6778d9
5
+ SHA512:
6
+ metadata.gz: a98ac529566451e8d0490ed66f4d5ab2c4e7e58b963d6645815402529c7d1fe6fb8fdcbd9bf3ebcd314c3da3c39dac234cf9ff5c1a25753502ba78bd013891b1
7
+ data.tar.gz: 102a8232c486c37e09d543190b0f375a752bfaf5d6adeb087019632e7b3f33931b4135e65b1e8223c60f47b9cfd772817ed8bb595358089345eea7282538dc9f
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *~
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lisp-rails-view.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 TAHARA Yoshinori
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.md ADDED
@@ -0,0 +1,37 @@
1
+ # lisp-rails-view
2
+
3
+ lisp-rails-view is a templating engine for HTML.
4
+
5
+ ## Installation
6
+
7
+ Install SBCL:
8
+
9
+ sudo apt-get install sbcl
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'lisp-rails-view'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ## Usage
20
+
21
+ index.html.lisp
22
+
23
+ ```
24
+ (:div#main
25
+ (:h3.title "title")
26
+ (:p#foo.bar "Hello"))
27
+ ```
28
+
29
+ see https://github.com/quek/lisp-rails-view/tree/master/examples
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ (:p "パーシャルの中です。まみむめも。")
@@ -0,0 +1,99 @@
1
+ (:h1.title "lisp-rails-view Lisp ビューを書く")
2
+
3
+ (:h2 "イストール")
4
+
5
+ (:p "あらかじめ SBCL をインストールしておいてください。")
6
+
7
+ (:h2 "使い方")
8
+
9
+ (:h3 "基本")
10
+
11
+ ;; CL なのでこんにふうにコメントアウトできる
12
+ #+ni
13
+ (:pre (WITH-OUTPUT-TO-STRING (*STANDARD-OUTPUT*) (ROOM)))
14
+
15
+ (:p.warning "b__ は予約語なので使えません。")
16
+
17
+ "文字列はそのまま出力。<p>"
18
+
19
+ (:p "タグはキーワードで書く。")
20
+
21
+ (:p "(setf (readtable-case *readtable*) :preserve) しているので大文字で書くと CL"
22
+ (:br)
23
+ (IF (EVENP (GET-UNIVERSAL-TIME))
24
+ "偶数"
25
+ "奇数"))
26
+
27
+ (:h3 "エスケープ")
28
+
29
+ (:p "エスケープされるはず。<script>alert(\"hello\");</script>&\"'")
30
+
31
+ (:h3 "Ruby のコード")
32
+
33
+ (:p "ふつうに . かスペースです。")
34
+
35
+ (:div
36
+ (:p "(= @facilities first name) => " (= @facilities first name))
37
+ (:p "(= @facilities.first.name) => "(= @facilities.first.name))
38
+ (:p "(= @facilities[1] name) => "(= @facilities[1] name)))
39
+
40
+ (:p "引数は括弧でかこってください。CL の都合上 : は \\ でエスケープしてください。")
41
+
42
+ (:p "(= Time.now) => "(= Time.now))
43
+ (:p "(= Time.now.to_s (\:datetime)) => "(= Time.now.to_s (\:datetime)))
44
+ (:p "(= @facilities.map (&\:name)) => "(= @facilities.map (&\:name)))
45
+ (:p "(= @facilities map (&\:name) join (\"、\")) => "(= @facilities map (&\:name) join ("、")))
46
+
47
+
48
+ (:h3 "each")
49
+
50
+ (:p "ブロックは lambda にしてください。")
51
+
52
+ (:p
53
+ (:pre "(:ul
54
+ (@facilities each (lambda (facility) (:li (= facility.name)))))")
55
+ (:ul
56
+ (@facilities each (lambda (facility)
57
+ (:li (= facility.name))))))
58
+
59
+ (:h3 "if")
60
+
61
+ (:p "if もなんとか書けます。")
62
+
63
+ (:p
64
+ (:pre
65
+ "(if (Time now to_i even?)
66
+ \"偶数\"
67
+ \"奇数\")")
68
+ (if (Time now to_i even?)
69
+ "偶数"
70
+ "奇数"))
71
+
72
+
73
+ (:h3 "render")
74
+
75
+ (:p "パーシャばもなんとか。")
76
+
77
+ (:p (:pre "(= render (\"partial\"))"))
78
+ (= render ("partial"))
79
+
80
+
81
+ (:h3 "form")
82
+
83
+ (:p "フォーム")
84
+
85
+ (:p (:pre "(= form_for (Facility first)
86
+ (lambda (f)
87
+ (:p "フォームの中です<p>")
88
+ (:p
89
+ (= f label (\:name))
90
+ (= f text_field (\:name))
91
+ (= f submit))))"))
92
+
93
+ (= form_for (Facility first)
94
+ (lambda (f)
95
+ (:p "フォームの中です<p>")
96
+ (:p
97
+ (= f label (\:name))
98
+ (= f text_field (\:name))
99
+ (= f submit))))
@@ -0,0 +1,6 @@
1
+ (:html
2
+ (:head
3
+ (:meta :charset "utf-8")
4
+ (:title "lisp-rails-view Lisp ビューを書く"))
5
+ (:body
6
+ (= yield)))
@@ -0,0 +1,39 @@
1
+ require "lisp-rails-view/version"
2
+
3
+ module LispRailsView
4
+ class Railtie < ::Rails::Railtie
5
+ initializer :lisp do |app|
6
+ ActiveSupport.on_load :action_view do
7
+ ActionView::Template.register_template_handler :lisp, LispHandler
8
+ end
9
+ end
10
+ end
11
+
12
+ class LispHandler
13
+
14
+ LISP = File.expand_path('../../lisp/lisp-rails-view.lisp', __FILE__)
15
+
16
+ def self.call(template)
17
+ file = template.identifier
18
+ x = `sbcl --script #{LISP} #{file}`
19
+ code = <<EOT
20
+ [].tap do |b__|
21
+ def b__.push(x)
22
+ if x.is_a?(Array)
23
+ x.map do |y|
24
+ push(y)
25
+ end
26
+ else
27
+ super(x.html_safe? ? x : ERB::Util.h(x))
28
+ end
29
+ end
30
+ #{x}
31
+ end.flatten.join.html_safe
32
+ EOT
33
+ Rails.logger.debug('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
34
+ Rails.logger.debug(code)
35
+ Rails.logger.debug('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
36
+ code
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module LispRailsView
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/lisp-rails-view/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["TAHARA Yoshinori"]
6
+ gem.email = ["read.eval.print@gmail.com"]
7
+ gem.description = %q{lisp-rails-view is a templating engine for HTML.}
8
+ gem.summary = %q{lisp-rails-view is a templating engine for HTML.}
9
+ gem.homepage = "https://github.com/quek/lisp-rails-view"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "lisp-rails-view"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = LispRailsView::VERSION
17
+
18
+ gem.add_development_dependency 'bundler'
19
+ gem.add_development_dependency 'rake'
20
+ end
@@ -0,0 +1,229 @@
1
+ (defpackage :lisp-rails-view
2
+ (:use :cl))
3
+
4
+ (in-package :lisp-rails-view)
5
+
6
+ (defvar *buffer* nil)
7
+
8
+ (defclass raw ()
9
+ ((value :initarg :value :accessor value)))
10
+
11
+ (defclass raw= (raw) ())
12
+
13
+ (defclass html-safe ()
14
+ ((value :initarg :value :accessor value)))
15
+
16
+ (defun raw (x)
17
+ (make-instance 'raw :value x))
18
+
19
+ (defun raw= (x)
20
+ (make-instance 'raw= :value x))
21
+
22
+ (defun html-safe (x)
23
+ (make-instance 'html-safe :value x))
24
+
25
+ (eval-when (:compile-toplevel :load-toplevel :execute)
26
+ (defmacro with-reader (&body body)
27
+ `(let ((*readtable* (copy-readtable nil)))
28
+ (setf (readtable-case *readtable*) :preserve)
29
+ ,@body)))
30
+
31
+ (defun call (template)
32
+ (with-reader (%call template))
33
+ (flush-buffer t))
34
+
35
+ (defun %call (template)
36
+ (with-open-file (in template)
37
+ (loop for form = (read in nil nil)
38
+ while form
39
+ do (%eval form))))
40
+
41
+ (defun flush-buffer (stream)
42
+ ;;TODO constant の連結
43
+ (loop for x in (nreverse *buffer*)
44
+ do (format stream "~a~%" (to-ruby-exp x))))
45
+
46
+ (defun emit (x)
47
+ (push x *buffer*))
48
+
49
+ (defun to-s (x)
50
+ (with-output-to-string (out)
51
+ (write-char #\" out)
52
+ (loop for c across (princ-to-string x)
53
+ do (cond ((char= c #\")
54
+ (write-string "\\\"" out))
55
+ (t
56
+ (write-char c out))))
57
+ (write-char #\" out)))
58
+
59
+ (defun to-ruby-token (x)
60
+ (typecase x
61
+ (string x
62
+ (to-s x))
63
+ (t x)))
64
+
65
+ (defmethod to-ruby-exp (x)
66
+ (with-output-to-string (out)
67
+ (write-string "b__.push(" out)
68
+ (write-string (to-s x) out)
69
+ (write-string ")" out)))
70
+
71
+ (defmethod to-ruby-exp ((x number))
72
+ (to-ruby-exp (princ-to-string x)))
73
+
74
+ (defmethod to-ruby-exp ((x raw))
75
+ (value x))
76
+
77
+ (defmethod to-ruby-exp ((x raw=))
78
+ (format nil "b__.push(~a)" (value x)))
79
+
80
+ (defmethod to-ruby-exp ((x html-safe))
81
+ (format nil "b__.push(~a.html_safe)" (to-s (value x))))
82
+
83
+
84
+ (defmethod %eval (x)
85
+ (emit x))
86
+
87
+ (defmethod %eval ((x null)))
88
+
89
+ (defmethod %eval ((x cons))
90
+ (cond ((eq '= (car x))
91
+ (emit (raw= (make-ruby-form (cdr x) t))))
92
+ ((keywordp (car x))
93
+ (process-tag x))
94
+ ((and (symbolp (car x))
95
+ (fboundp (car x)))
96
+ (emit (eval x)))
97
+ (t
98
+ (emit (raw (make-ruby-form x))))))
99
+
100
+ (defun process-tag (form)
101
+ (multiple-value-bind (tag id classes) (parse-tag (car form))
102
+ (multiple-value-bind (attributes body /-p) (parse-tag-args (cdr form))
103
+ (when classes
104
+ (let ((kv (assoc "class" attributes :test #'string=)))
105
+ (when kv
106
+ (setf (cdr kv) `(append ',classes
107
+ (ensure-list ,(cdr kv)))
108
+ classes nil))))
109
+ (emit (html-safe (with-output-to-string (out)
110
+ (format out "<~a" tag)
111
+ (when id
112
+ (format out " id=\"~a\"" id))
113
+ (when classes
114
+ (format out " class=\"~{~a~^ ~}\"" classes))
115
+ (loop for (k . v) in attributes do
116
+ (if (constantp v)
117
+ (if (eq v t)
118
+ (format out " ~a" k)
119
+ (format out " ~a=\"~a\"" k v))
120
+ (format out "#{~a == true ? \"~a\" : \"~a=\"~a\"\"}" v k k v)))
121
+ (if /-p
122
+ (write-string " />" out)
123
+ (write-string ">" out)))))
124
+ (loop for i in body
125
+ do (%eval i))
126
+ (emit (html-safe (format nil "</~a>" tag))))))
127
+
128
+ (defun parse-tag (tag)
129
+ (let* ((str (string-downcase (symbol-name tag)))
130
+ (p# (position #\# str))
131
+ (p. (position #\. str)))
132
+ (cond ((and (not p#) (not p.))
133
+ str)
134
+ ((and p# (not p.))
135
+ (values (subseq str 0 p#)
136
+ (subseq str (1+ p#))))
137
+ ((and (not p#) p.)
138
+ (values (subseq str 0 p.)
139
+ nil
140
+ #1=(loop for start = (1+ p.) then (1+ end)
141
+ for end = (position #\. str :start start)
142
+ collect (subseq str start end)
143
+ unless end
144
+ do (loop-finish))))
145
+ (t
146
+ (values (subseq str 0 p#)
147
+ (subseq str (1+ p#) p.)
148
+ #1#)))))
149
+
150
+ (defun parse-tag-args (args)
151
+ (let (attributes)
152
+ (labels ((f (args)
153
+ (if (and (consp args)
154
+ (keywordp (car args)))
155
+ (progn
156
+ (push (cons (string-downcase (car args)) (cadr args)) attributes)
157
+ (f (cddr args)))
158
+ (values (nreverse attributes)
159
+ args
160
+ (if (atom args)
161
+ args
162
+ (cdr (last args)))))))
163
+ (f args))))
164
+
165
+ (defun blockp (form)
166
+ (and (consp (car (last form)))
167
+ (string-equal "lambda" (caar (last form)))))
168
+
169
+ (defun make-ruby-form (form &optional new-buffer-p)
170
+ (with-output-to-string (out)
171
+ (let* ((blockp (blockp form))
172
+ (block-form (and blockp (cdar (last form))))
173
+ (main-form (if blockp (butlast form) form)))
174
+ (make-ruby-main-form (car main-form) (cdr main-form) out)
175
+ (when block-form
176
+ (format out "{~a}" (make-ruby-block block-form new-buffer-p))))))
177
+
178
+ (defmethod make-ruby-main-form (first rest out)
179
+ (format out "~a" (to-ruby-token first))
180
+ (loop for i in rest
181
+ do (if (consp i)
182
+ (format out "(~{~a~^, ~})" (mapcar #'make-ruby-form (list i)))
183
+ (progn
184
+ (write-char #\. out)
185
+ (format out "~a" (to-ruby-token i))))))
186
+
187
+ (defmethod make-ruby-main-form ((first (eql '|if|)) rest out)
188
+ (format out "if ~a~%~aelse~%~aend"
189
+ (make-ruby-form (car rest))
190
+ (make-ruby-block-body (ensure-list (cadr rest)))
191
+ (make-ruby-block-body (ensure-list (caddr rest)))))
192
+
193
+ (defun make-ruby-block (form &optional new-buffer-p)
194
+ (with-output-to-string (out)
195
+ (let ((args (car form))
196
+ (body (make-ruby-block-body (cdr form))))
197
+ (when args
198
+ (format out "|~{~a~^, ~}|~%" args))
199
+ (if new-buffer-p
200
+ (format out "
201
+ [].tap do |b__|
202
+ def b__.push(x)
203
+ if x.is_a?(Array)
204
+ x.map do |y|
205
+ push(y)
206
+ end
207
+ else
208
+ super(x.html_safe? ? x : ERB::Util.h(x))
209
+ end
210
+ end
211
+ ~a
212
+ end.flatten.join.html_safe~%" body)
213
+ (format out "~a" body)))))
214
+
215
+ (defun make-ruby-block-body (form)
216
+ (let ((*buffer* nil))
217
+ (loop for i in form
218
+ do (%eval i))
219
+ (with-output-to-string (out)
220
+ (flush-buffer out))))
221
+
222
+ (defun ensure-list (x)
223
+ (if (consp x)
224
+ x
225
+ (list x)))
226
+
227
+ (let ((template (cadr sb-ext:*posix-argv*)))
228
+ (when template
229
+ (call template)))
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lisp-rails-view
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - TAHARA Yoshinori
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: lisp-rails-view is a templating engine for HTML.
42
+ email:
43
+ - read.eval.print@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE
51
+ - README.md
52
+ - Rakefile
53
+ - examples/_partial.html.lisp
54
+ - examples/index.html.lisp
55
+ - examples/layout.html.lisp
56
+ - lib/lisp-rails-view.rb
57
+ - lib/lisp-rails-view/version.rb
58
+ - lisp-rails-view.gemspec
59
+ - lisp/lisp-rails-view.lisp
60
+ homepage: https://github.com/quek/lisp-rails-view
61
+ licenses: []
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.2.1
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: lisp-rails-view is a templating engine for HTML.
83
+ test_files: []