slack-block-kit 0.1.0
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/README.md +62 -0
- data/Rakefile +6 -0
- data/bin/console +27 -0
- data/bin/setup +8 -0
- data/examples/slack_template_00.rb +46 -0
- data/examples/slack_template_01.rb +22 -0
- data/examples/slack_template_02.rb +28 -0
- data/examples/slack_template_03.rb +57 -0
- data/examples/slack_template_04.rb +29 -0
- data/examples/slack_template_05.rb +12 -0
- data/examples/slack_template_06.rb +53 -0
- data/examples/slack_template_07.rb +74 -0
- data/examples/slack_template_08.rb +77 -0
- data/examples/slack_template_09.rb +53 -0
- data/lib/slack-block-kit.rb +1 -0
- data/lib/slack/block_kit.rb +38 -0
- data/lib/slack/block_kit/block.rb +41 -0
- data/lib/slack/block_kit/block/actions_block.rb +35 -0
- data/lib/slack/block_kit/block/context_block.rb +30 -0
- data/lib/slack/block_kit/block/divider_block.rb +17 -0
- data/lib/slack/block_kit/block/image_block.rb +44 -0
- data/lib/slack/block_kit/block/section_block.rb +55 -0
- data/lib/slack/block_kit/composition_objects/confirmation_dialog.rb +59 -0
- data/lib/slack/block_kit/composition_objects/filter.rb +38 -0
- data/lib/slack/block_kit/composition_objects/option.rb +57 -0
- data/lib/slack/block_kit/composition_objects/option_group.rb +34 -0
- data/lib/slack/block_kit/composition_objects/text.rb +61 -0
- data/lib/slack/block_kit/element.rb +41 -0
- data/lib/slack/block_kit/element/button_element.rb +48 -0
- data/lib/slack/block_kit/element/channels_select_element.rb +31 -0
- data/lib/slack/block_kit/element/conversations_select_element.rb +43 -0
- data/lib/slack/block_kit/element/date_picker_element.rb +56 -0
- data/lib/slack/block_kit/element/external_select_element.rb +38 -0
- data/lib/slack/block_kit/element/image_element.rb +26 -0
- data/lib/slack/block_kit/element/multi_channels_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_conversations_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_external_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_static_select_element.rb +38 -0
- data/lib/slack/block_kit/element/multi_users_select_element.rb +39 -0
- data/lib/slack/block_kit/element/overflow_element.rb +42 -0
- data/lib/slack/block_kit/element/select_element.rb +45 -0
- data/lib/slack/block_kit/element/static_select_element.rb +46 -0
- data/lib/slack/block_kit/element/users_select_element.rb +24 -0
- data/lib/slack/block_kit/execution_context.rb +64 -0
- data/lib/slack/block_kit/refinements/hash_compact.rb +15 -0
- data/lib/slack/block_kit/type_restricted_array.rb +21 -0
- data/lib/slack/block_kit/version.rb +5 -0
- data/slack-block-kit.gemspec +29 -0
- metadata +166 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
[ SectionBlock[text: Text[mrkdwn: ":mag: Search results for #{Bold['Cata']}"]],
|
2
|
+
DividerBlock[],
|
3
|
+
SectionBlock[
|
4
|
+
text: Text[mrkdwn: [
|
5
|
+
Bold[Link['fakeLink.toYourApp.com', 'Use Case Catalogue']],
|
6
|
+
"Use Case Catalogue for the following departments/roles..."
|
7
|
+
]],
|
8
|
+
accessory: StaticSelectElement[
|
9
|
+
placeholder: Text[plain_text: 'Manage', emoji: true],
|
10
|
+
options: [
|
11
|
+
Option[text: Text[plain_text: 'Edit it', emoji: true], value: 'value-0'],
|
12
|
+
Option[text: Text[plain_text: 'Read it', emoji: true], value: 'value-1'],
|
13
|
+
Option[text: Text[plain_text: 'Save it', emoji: true], value: 'value-2']
|
14
|
+
]
|
15
|
+
]
|
16
|
+
],
|
17
|
+
SectionBlock[
|
18
|
+
text: Text[mrkdwn: [
|
19
|
+
Bold[Link['fakeLink.toYourApp.com', 'Customer Support - Workflow Diagram Catalogue']],
|
20
|
+
"This resource was put together by members of..."
|
21
|
+
]],
|
22
|
+
accessory: StaticSelectElement[
|
23
|
+
placeholder: Text[plain_text: 'Manage', emoji: true],
|
24
|
+
options: [
|
25
|
+
Option[text: Text[plain_text: 'Manage it', emoji: true], value: 'value-0'],
|
26
|
+
Option[text: Text[plain_text: 'Read it', emoji: true], value: 'value-1'],
|
27
|
+
Option[text: Text[plain_text: 'Save it', emoji: true], value: 'value-2']
|
28
|
+
]
|
29
|
+
]
|
30
|
+
],
|
31
|
+
SectionBlock[
|
32
|
+
text: Text[mrkdwn: [
|
33
|
+
Bold[Link['fakeLink.toYourApp.com', 'Self-Serve Learning Options Catalogue']],
|
34
|
+
"See the learning and development options we..."
|
35
|
+
]],
|
36
|
+
accessory: StaticSelectElement[
|
37
|
+
placeholder: Text[plain_text: 'Manage', emoji: true],
|
38
|
+
options: [
|
39
|
+
Option[text: Text[plain_text: 'Manage it', emoji: true], value: 'value-0'],
|
40
|
+
Option[text: Text[plain_text: 'Read it', emoji: true], value: 'value-1'],
|
41
|
+
Option[text: Text[plain_text: 'Save it', emoji: true], value: 'value-2']
|
42
|
+
]
|
43
|
+
]
|
44
|
+
],
|
45
|
+
SectionBlock[
|
46
|
+
text: Text[mrkdwn: [
|
47
|
+
Bold[Link['fakeLink.toYourApp.com', 'Use Case Catalogue - CF Presentation - [June 12, 2018]']],
|
48
|
+
"This is presentation will continue to be updated as..."
|
49
|
+
]],
|
50
|
+
accessory: StaticSelectElement[
|
51
|
+
placeholder: Text[plain_text: 'Manage', emoji: true],
|
52
|
+
options: [
|
53
|
+
Option[text: Text[plain_text: 'Manage it', emoji: true], value: 'value-0'],
|
54
|
+
Option[text: Text[plain_text: 'Read it', emoji: true], value: 'value-1'],
|
55
|
+
Option[text: Text[plain_text: 'Save it', emoji: true], value: 'value-2']
|
56
|
+
]
|
57
|
+
]
|
58
|
+
],
|
59
|
+
SectionBlock[
|
60
|
+
text: Text[mrkdwn: [
|
61
|
+
Bold[Link['fakeLink.toYourApp.com', 'Comprehensive Benefits Catalogue - 2019']],
|
62
|
+
"Information about all the benfits we offer is..."
|
63
|
+
]],
|
64
|
+
accessory: StaticSelectElement[
|
65
|
+
placeholder: Text[plain_text: 'Manage', emoji: true],
|
66
|
+
options: [
|
67
|
+
Option[text: Text[plain_text: 'Manage it', emoji: true], value: 'value-0'],
|
68
|
+
Option[text: Text[plain_text: 'Read it', emoji: true], value: 'value-1'],
|
69
|
+
Option[text: Text[plain_text: 'Save it', emoji: true], value: 'value-2']
|
70
|
+
]
|
71
|
+
]
|
72
|
+
],
|
73
|
+
DividerBlock[],
|
74
|
+
ActionsBlock[elements: [
|
75
|
+
ButtonElement[text: Text[plain_text: 'Next 5 Results', emoji: true], value: 'click_me_123']
|
76
|
+
]]
|
77
|
+
]
|
@@ -0,0 +1,53 @@
|
|
1
|
+
[ SectionBlock[text: Text[mrkdwn: ":newspaper: #{Bold['Paper Company Newsletter']} :newspaper:"]],
|
2
|
+
ContextBlock[elements: [Text[mrkdwn: "#{Bold['November 12, 2019']} | Sales Team Announcements"]]],
|
3
|
+
DividerBlock[],
|
4
|
+
SectionBlock[text: Text[mrkdwn: " :loud_sound: #{Bold['IN CASE YOU MISSED IT']} :loud_sound:"]],
|
5
|
+
SectionBlock[
|
6
|
+
text: Text[mrkdwn: "Replay our screening of #{Bold['Threat Level Midnight']} and pick up a copy of the DVD to give to your customers at the front desk."],
|
7
|
+
accessory: ButtonElement[text: Text[plain_text: 'Watch Now', emoji: true]]
|
8
|
+
],
|
9
|
+
SectionBlock[
|
10
|
+
text: Text[mrkdwn: [
|
11
|
+
"The *2019 Dundies* happened. ",
|
12
|
+
"Awards were given, heroes were recognized. ",
|
13
|
+
"Check out *#dundies-2019* to see who won awards."
|
14
|
+
]]
|
15
|
+
],
|
16
|
+
DividerBlock[],
|
17
|
+
SectionBlock[text: Text[mrkdwn: ":calendar: | #{Bold['UPCOMING EVENTS']} | :calendar: "]],
|
18
|
+
SectionBlock[
|
19
|
+
text: Text[mrkdwn: "#{Code['11/20-11/22']} #{Bold['Beet the Competition']} #{Italic[' annual retreat at Schrute Farms']}"],
|
20
|
+
accessory: ButtonElement[text: Text[plain_text: 'RSVP', emoji: true]]
|
21
|
+
],
|
22
|
+
SectionBlock[
|
23
|
+
text: Text[mrkdwn: "#{Code['12/01']} #{Bold["Toby's Going Away Party"]} at #{Italic['Benihana']}"],
|
24
|
+
accessory: ButtonElement[text: Text[plain_text: 'Learn More', emoji: true]]
|
25
|
+
],
|
26
|
+
SectionBlock[
|
27
|
+
text: Text[mrkdwn: "#{Code['11/13']} :pretzel: #{Bold['Pretzel Day']} :pretzel: at #{Italic['Scranton Office']}"],
|
28
|
+
accessory: ButtonElement[text: Text[plain_text: 'RSVP', emoji: true]]
|
29
|
+
],
|
30
|
+
DividerBlock[],
|
31
|
+
SectionBlock[text: Text[mrkdwn: ":calendar: | #{Bold['PAST EVENTS']} | :calendar: "]],
|
32
|
+
SectionBlock[
|
33
|
+
text: Text[mrkdwn: "#{Code['10/21']} #{Bold['Conference Room Meeting']}"],
|
34
|
+
accessory: ButtonElement[text: Text[plain_text: 'Watch Recording', emoji: true]]
|
35
|
+
],
|
36
|
+
DividerBlock[],
|
37
|
+
SectionBlock[text: Text[mrkdwn: Bold['FOR YOUR INFORMATION']]],
|
38
|
+
SectionBlock[text: Text[mrkdwn: ":printer: #{Bold['Sabre Printers']} are no longer catching on fire! The newest version of our printers are safe to use. Make sure to tell your customers today.", verbatim: false]],
|
39
|
+
DividerBlock[],
|
40
|
+
SectionBlock[text: Text[mrkdwn: [
|
41
|
+
"Please join me in welcoming our 3 #{Bold['new hires']} to the Paper Company family! ",
|
42
|
+
nil,
|
43
|
+
" #{Bold['Robert California']}, CEO ",
|
44
|
+
nil,
|
45
|
+
" #{Bold['Ryan Howard']}, Temp ",
|
46
|
+
nil,
|
47
|
+
" #{Bold['Erin Hannon']}, Receptionist "
|
48
|
+
]]],
|
49
|
+
DividerBlock[],
|
50
|
+
ContextBlock[elements: [
|
51
|
+
Text[mrkdwn: ":pushpin: Do you have something to include in the newsletter? Here's #{Bold['how to submit content']}."]
|
52
|
+
]]
|
53
|
+
]
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'slack/block_kit'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'block_kit/type_restricted_array'
|
4
|
+
require_relative 'block_kit/refinements/hash_compact'
|
5
|
+
|
6
|
+
require_relative 'block_kit/block'
|
7
|
+
require_relative 'block_kit/block/actions_block'
|
8
|
+
require_relative 'block_kit/block/context_block'
|
9
|
+
require_relative 'block_kit/block/divider_block'
|
10
|
+
require_relative 'block_kit/block/image_block'
|
11
|
+
require_relative 'block_kit/block/section_block'
|
12
|
+
|
13
|
+
require_relative 'block_kit/composition_objects/confirmation_dialog'
|
14
|
+
require_relative 'block_kit/composition_objects/filter'
|
15
|
+
require_relative 'block_kit/composition_objects/option'
|
16
|
+
require_relative 'block_kit/composition_objects/option_group'
|
17
|
+
require_relative 'block_kit/composition_objects/text'
|
18
|
+
|
19
|
+
require_relative 'block_kit/element'
|
20
|
+
require_relative 'block_kit/element/button_element'
|
21
|
+
require_relative 'block_kit/element/date_picker_element'
|
22
|
+
require_relative 'block_kit/element/image_element'
|
23
|
+
require_relative 'block_kit/element/overflow_element'
|
24
|
+
|
25
|
+
require_relative 'block_kit/element/select_element'
|
26
|
+
require_relative 'block_kit/element/channels_select_element'
|
27
|
+
require_relative 'block_kit/element/conversations_select_element'
|
28
|
+
require_relative 'block_kit/element/external_select_element'
|
29
|
+
require_relative 'block_kit/element/static_select_element'
|
30
|
+
require_relative 'block_kit/element/users_select_element'
|
31
|
+
|
32
|
+
require_relative 'block_kit/element/multi_channels_select_element'
|
33
|
+
require_relative 'block_kit/element/multi_conversations_select_element'
|
34
|
+
require_relative 'block_kit/element/multi_external_select_element'
|
35
|
+
require_relative 'block_kit/element/multi_static_select_element'
|
36
|
+
require_relative 'block_kit/element/multi_users_select_element'
|
37
|
+
|
38
|
+
require_relative 'block_kit/execution_context'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Block
|
6
|
+
attr_reader :block_id
|
7
|
+
|
8
|
+
def self.populate(hash, object)
|
9
|
+
object.block_id = hash[:block_id] if hash.key?(:block_id)
|
10
|
+
raise ArgumentError, "invalid #{name}" unless object.valid?
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.[](hash)
|
14
|
+
new.tap { |obj| populate(hash, obj) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def block_id=(obj)
|
18
|
+
raise TypeError, 'block_id must be a string' unless obj.respond_to?(:to_str)
|
19
|
+
raise RangeError, 'block_id must be max 255 characters' unless obj.size <= 255
|
20
|
+
|
21
|
+
@block_id = obj.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def type
|
25
|
+
@type ||= self.class.name
|
26
|
+
.split('::')
|
27
|
+
.last.chomp('Block')
|
28
|
+
.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_h
|
36
|
+
{ type: type,
|
37
|
+
block_id: block_id }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Block
|
6
|
+
class ActionsBlock < Block
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_accessor :elements
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
hash[:elements].each(&object.elements.method(:<<))
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@elements = TypeRestrictedArray.new(
|
16
|
+
Element::ButtonElement,
|
17
|
+
Element::SelectElement,
|
18
|
+
Element::OverflowElement,
|
19
|
+
Element::DatePickerElement
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid?
|
24
|
+
!@elements.empty? && @elements.size <= 5
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
super.merge(
|
29
|
+
elements: elements.map(&:to_h)
|
30
|
+
).compact
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Block
|
6
|
+
class ContextBlock < Block
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_accessor :elements
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
hash[:elements].each(&object.elements.method(:<<))
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@elements = TypeRestrictedArray.new(Element, CompositionObjects::Text)
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid?
|
19
|
+
!@elements.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_h
|
23
|
+
super.merge(
|
24
|
+
elements: elements.map(&:to_h)
|
25
|
+
).compact
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Block
|
6
|
+
class ImageBlock < Block
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_accessor :image_url, :alt_text, :title
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
object.image_url = hash.fetch(:image_url)
|
12
|
+
object.alt_text = hash.fetch(:alt_text)
|
13
|
+
object.title = hash[:title] if hash.key?(:title)
|
14
|
+
end
|
15
|
+
|
16
|
+
def title=(obj)
|
17
|
+
raise TypeError, 'title must be a Text Object' unless obj.is_a?(CompositionObjects::Text)
|
18
|
+
|
19
|
+
@title = obj
|
20
|
+
end
|
21
|
+
|
22
|
+
def image_url=(url)
|
23
|
+
raise RangeError, 'image_url is max 3000 characters' unless url.size <= 3000
|
24
|
+
|
25
|
+
@image_url = url
|
26
|
+
end
|
27
|
+
|
28
|
+
def alt_text=(text)
|
29
|
+
raise RangeError, 'alt_text is max 2000 characters' unless text.size <= 2000
|
30
|
+
|
31
|
+
@alt_text = text
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_h
|
35
|
+
super.merge(
|
36
|
+
image_url: image_url,
|
37
|
+
alt_text: alt_text,
|
38
|
+
title: title&.to_h
|
39
|
+
).compact
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Block
|
6
|
+
class SectionBlock < Block
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :text, :fields, :accessory
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
object.accessory = hash[:accessory] if hash.key?(:accessory)
|
12
|
+
if hash.key?(:text) then object.text = hash[:text]
|
13
|
+
elsif hash.key?(:fields) then hash[:fields].each(&object.fields.method(:<<))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@fields = TypeRestrictedArray.new(CompositionObjects::Text)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Either text or fields must exist and be non-empty.
|
22
|
+
def valid?
|
23
|
+
if @text.nil? || @text.empty? then !@fields.empty?
|
24
|
+
else !@text&.empty?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def text=(obj)
|
29
|
+
raise TypeError, 'text must be a Text Object' unless obj.is_a?(CompositionObjects::Text)
|
30
|
+
|
31
|
+
@text = obj
|
32
|
+
end
|
33
|
+
|
34
|
+
def accessory=(elem)
|
35
|
+
raise TypeError, 'accessory must be a block element' unless elem.is_a?(Element)
|
36
|
+
|
37
|
+
@accessory = elem
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h
|
41
|
+
if text && text.text.size > 3000
|
42
|
+
raise RangeError, 'text in SectionBlock has max 3000 characters'
|
43
|
+
end
|
44
|
+
|
45
|
+
super.merge(
|
46
|
+
block_id: block_id,
|
47
|
+
text: text&.to_h,
|
48
|
+
fields: fields.map(&:to_h),
|
49
|
+
accessory: accessory&.to_h
|
50
|
+
).compact
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module CompositionObjects
|
6
|
+
class ConfirmationDialog
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :title, :text, :confirm, :deny
|
9
|
+
|
10
|
+
def self.[](hash)
|
11
|
+
new.tap do |object|
|
12
|
+
object.title = hash.fetch(:title)
|
13
|
+
object.text = hash.fetch(:text)
|
14
|
+
object.confirm = hash.fetch(:confirm)
|
15
|
+
object.deny = hash.fetch(:deny)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def title=(obj)
|
20
|
+
raise TypeError, 'title must be a Text Object' unless obj.is_a?(Text)
|
21
|
+
raise TypeError, 'title must be plain_text' unless obj.type == :plain_text
|
22
|
+
raise RangeError, 'title is max 100 characters' unless obj.text.size <= 100
|
23
|
+
|
24
|
+
@title = obj
|
25
|
+
end
|
26
|
+
|
27
|
+
def text=(obj)
|
28
|
+
raise TypeError, 'text must be a Text Object' unless obj.is_a?(Text)
|
29
|
+
raise RangeError, 'text is max 300 characters' unless obj.text.size <= 300
|
30
|
+
|
31
|
+
@text = obj
|
32
|
+
end
|
33
|
+
|
34
|
+
def confirm=(obj)
|
35
|
+
raise TypeError, 'confirm must be a Text Object' unless obj.is_a?(Text)
|
36
|
+
raise TypeError, 'confirm must be plain_text' unless obj.type == :plain_text
|
37
|
+
raise RangeError, 'confirm is max 30 characters' unless obj.text.size <= 30
|
38
|
+
|
39
|
+
@confirm = obj
|
40
|
+
end
|
41
|
+
|
42
|
+
def deny=(obj)
|
43
|
+
raise TypeError, 'deny must be a Text Object' unless obj.is_a?(Text)
|
44
|
+
raise TypeError, 'deny must be plain_text' unless obj.type == :plain_text
|
45
|
+
raise RangeError, 'deny is max 30 characters' unless obj.text.size <= 30
|
46
|
+
|
47
|
+
@deny = obj
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_h
|
51
|
+
{ title: title.to_h,
|
52
|
+
text: text.to_h,
|
53
|
+
confirm: confirm.to_h,
|
54
|
+
deny: deny.to_h }.compact
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|