leanweb 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54fc1b8b4dff318eb3ccc51e8f0862706c0b8de9879dadf403580f00a224b9df
4
- data.tar.gz: e2a5d17a9f7a2f13f0cb2983031f91127387021a26d70a7bc91e0722ffb19bf3
3
+ metadata.gz: f4420d0acf838a96016cabcbdf4fb5977044c4c43c7102bbb7c520dab34a3908
4
+ data.tar.gz: 861d7f89f86f9749ac69e007ffd23218047f6cabf825a53074df2aab953e9bb3
5
5
  SHA512:
6
- metadata.gz: 0563e596c38aefdd7af7150ed4f87dbbb55c6bee5459d397574e5fb1da18fe31e5091d6f8346e952729118fed9fda8f6e0b3f2579e0b39fc54d426cee76b81ed
7
- data.tar.gz: 579991147e69766158a1168d28ec58f8da90a94ad4383e2fe8001b15cc4460895892600d53968e063e067a7be2c12347f25e37ec94cb2237e5adc32c04333a1a
6
+ metadata.gz: 3377a07bfdee4a0fe5ebfdd40d3094786ac204b2301eafbf796b296bcce86ab6728352246f74abea581d5910f0f3868d5d11c7706ee4f61ce5275f74914365c4
7
+ data.tar.gz: 616f2bcc6979253f43d20135a72a3537c6eb3680278c39fa73c879e0a088434c1242f10f200202ab0ec5533c746cab0ca971e655ed79956cdd3f3bca6886bac8
@@ -12,6 +12,7 @@ require 'net/smtp'
12
12
  require 'securerandom'
13
13
  require 'socket'
14
14
  require 'time'
15
+ require 'uri/mailto'
15
16
 
16
17
  # Send an email with SMTP easily.
17
18
  #
@@ -25,27 +26,32 @@ require 'time'
25
26
  # - SMTP_FROM: In the format `Name <user@mail>` or `user@mail`.
26
27
  #
27
28
  # @example Single address
28
- # LeanMail.deliver('to@mail', 'subject', 'body')
29
+ # LeanMail.deliver('to@mail', 'subject', 'body', reply_to: 'to@other.host')
29
30
  #
30
31
  # @example Multiple addresses
31
32
  # LeanMail.deliver(['to@mail', 'to2@mail'], 'subject', 'body')
32
33
  module LeanMail
33
34
  # RFC 2821 message data representation.
34
35
  class Data
35
- attr_reader :from, :to, :subject, :message
36
+ attr_reader :from, :to, :subject, :message, :reply_to
37
+
38
+ def initialize(from, to, subject, message, reply_to: nil)
39
+ self.class.validate_recipients(to)
40
+ self.class.validate_recipients(reply_to) if reply_to
36
41
 
37
- def initialize(from, to, subject, message)
38
42
  @from = from
39
43
  @to = to
40
44
  @subject = subject
41
45
  @message = message
46
+ @reply_to = reply_to
42
47
  end
43
48
 
44
49
  def to_s
45
50
  <<~MAIL
46
51
  Content-type: text/plain; charset=UTF-8
47
52
  From: #{@from}
48
- To: #{to.instance_of?(Array) ? to.join(', ') : to}
53
+ To: #{@to.instance_of?(Array) ? @to.join(', ') : @to}
54
+ Reply-To: #{@reply_to || @from}
49
55
  Subject: =?UTF-8?B?#{Base64.strict_encode64(subject)}?=
50
56
  Date: #{Time.new.rfc2822}
51
57
  Message-Id: <#{SecureRandom.uuid}@#{Socket.gethostname}>
@@ -53,6 +59,29 @@ module LeanMail
53
59
  #{@message}
54
60
  MAIL
55
61
  end
62
+
63
+ class << self
64
+ def validate_recipients(recipients)
65
+ return recipients.each{ |recipient| validate_recipients(recipient) } if
66
+ recipients.instance_of?(Array)
67
+
68
+ raise(ArgumentError, "#{recipients} is not a valid recipient") unless
69
+ URI::MailTo::EMAIL_REGEXP.match?(extract_addr(recipients))
70
+ end
71
+
72
+ def extract_addr(str)
73
+ match = str.match(/\A[^\n\r<]+<([^\n\r>]+)>\z/)
74
+ return match[1] if match
75
+
76
+ str
77
+ end
78
+
79
+ def extract_addrs(to)
80
+ return to.map{ |addr| extract_addr(addr) } if to.instance_of?(Array)
81
+
82
+ extract_addr(to)
83
+ end
84
+ end
56
85
  end
57
86
 
58
87
  # Email deliverer.
@@ -76,12 +105,17 @@ module LeanMail
76
105
  # @param to [Array, String] In the format `Name <user@mail>` or `user@mail`.
77
106
  # @param subject [String]
78
107
  # @param body [String]
108
+ # @param reply_to [Array, String] In the same format as `to`.
79
109
  # @return [Deliver]
80
- def call(to, subject, body)
81
- @data = Data.new(@from, to, subject, body)
110
+ def call(to, subject, body, reply_to: nil)
111
+ @data = Data.new(@from, to, subject, body, reply_to: reply_to)
82
112
 
83
113
  @smtp.start(Socket.gethostname, @user, @password, :plain) do |smtp|
84
- smtp.send_message(@data.to_s, extract_addr(@from), extract_addrs(to))
114
+ smtp.send_message(
115
+ @data.to_s,
116
+ Data.extract_addr(@from),
117
+ Data.extract_addrs(to)
118
+ )
85
119
  end
86
120
 
87
121
  self
@@ -100,19 +134,6 @@ module LeanMail
100
134
  when 'starttls' then @smtp.enable_starttls
101
135
  end
102
136
  end
103
-
104
- def extract_addr(str)
105
- match = str.match(%r{<([^/]+)>})
106
- return match[1] if match
107
-
108
- str
109
- end
110
-
111
- def extract_addrs(to)
112
- return to.map{ |addr| extract_addr(addr) } if to.instance_of?(Array)
113
-
114
- extract_addr(to)
115
- end
116
137
  end
117
138
 
118
139
  # Deliver email.
@@ -120,8 +141,9 @@ module LeanMail
120
141
  # @param to [Array, String] In the format `Name <user@mail>` or `user@mail`.
121
142
  # @param subject [String]
122
143
  # @param body [String]
144
+ # @param reply_to [Array, String] In the same format as `to`.
123
145
  # @return [Deliver]
124
- def self.deliver(to, subject, body)
125
- LeanMail::Deliver.new.call(to, subject, body)
146
+ def self.deliver(to, subject, body, reply_to: nil)
147
+ LeanMail::Deliver.new.call(to, subject, body, reply_to: reply_to)
126
148
  end
127
149
  end
data/lib/leanweb/route.rb CHANGED
@@ -72,11 +72,6 @@ module LeanWeb
72
72
  return respond_proc(request) if @action.instance_of?(Proc)
73
73
 
74
74
  respond_method(request)
75
- rescue NoMethodError
76
- raise unless @static == true && (view_path = guess_view_path)
77
-
78
- controller = default_controller_class.new(self)
79
- controller.default_static_action(view_path)
80
75
  end
81
76
 
82
77
  # String path, independent if {#path} is Regexp or String.
@@ -159,14 +154,28 @@ module LeanWeb
159
154
  Controller
160
155
  end
161
156
 
157
+ def default_static_action
158
+ default_controller_class.new(self).default_static_action(guess_view_path)
159
+ end
160
+
161
+ def controller_for_request(request)
162
+ require_relative("#{CONTROLLER_PATH}/#{@action.controller.to_s.snakeize}")
163
+ Object.const_get(@action.controller).new(self, request)
164
+ rescue LoadError
165
+ nil
166
+ end
167
+
162
168
  # @param request [Rack::Request]
163
169
  # @return [Array] a valid Rack response.
164
170
  def respond_method(request)
165
171
  params = action_params(request.path)
166
- require_relative("#{CONTROLLER_PATH}/#{@action.controller.to_s.snakeize}")
167
- controller = Object.const_get(@action.controller).new(self, request)
168
- return controller.public_send(@action.action, **params) \
169
- if params.instance_of?(Hash)
172
+ controller = controller_for_request(request)
173
+
174
+ return default_static_action unless
175
+ controller&.class&.method_defined?(@action.action)
176
+
177
+ return controller.public_send(@action.action, **params) if
178
+ params.instance_of?(Hash)
170
179
 
171
180
  controller.public_send(@action.action, *params)
172
181
  end
@@ -9,5 +9,5 @@
9
9
 
10
10
 
11
11
  module LeanWeb
12
- VERSION = '0.5.1'
12
+ VERSION = '0.5.3'
13
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leanweb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Freeman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-13 00:00:00.000000000 Z
11
+ date: 2023-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -222,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
222
  - !ruby/object:Gem::Version
223
223
  version: '0'
224
224
  requirements: []
225
- rubygems_version: 3.4.7
225
+ rubygems_version: 3.4.10
226
226
  signing_key:
227
227
  specification_version: 4
228
228
  summary: LeanWeb is a minimal hybrid static / dynamic web framework