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,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module CompositionObjects
|
6
|
+
class Filter
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :include, :exclude_external_shared_channels, :exclude_bot_users
|
9
|
+
|
10
|
+
def self.[](hash)
|
11
|
+
new.tap do |object|
|
12
|
+
hash[:include].each(&object.include.method(:<<))
|
13
|
+
object.exclude_external_shared_channels! if hash[:exclude_external_shared_channels]
|
14
|
+
object.exclude_bot_users! if hash[:exclude_bot_users]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@include = TypeRestrictedArray.new(String)
|
20
|
+
end
|
21
|
+
|
22
|
+
def exclude_external_shared_channels!
|
23
|
+
@exclude_external_shared_channels = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def exclude_bot_users!
|
27
|
+
@exclude_bot_users = true
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_h
|
31
|
+
{ include: self.include,
|
32
|
+
exclude_external_shared_channels: exclude_external_shared_channels,
|
33
|
+
exclude_bot_users: exclude_bot_users }.compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module CompositionObjects
|
6
|
+
class Option
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :text, :value, :description, :url
|
9
|
+
|
10
|
+
def self.[](hash)
|
11
|
+
new.tap do |object|
|
12
|
+
object.text = hash.fetch(:text)
|
13
|
+
object.value = hash.fetch(:value)
|
14
|
+
object.description = hash[:description] if hash.key?(:description)
|
15
|
+
object.url = hash[:url] if hash.key?(:url)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def text=(obj)
|
20
|
+
raise TypeError, 'text must be a Text Object' unless obj.is_a?(Text)
|
21
|
+
raise RangeError, 'text is max 75 characters' unless obj.text.size <= 75
|
22
|
+
|
23
|
+
@text = obj
|
24
|
+
end
|
25
|
+
|
26
|
+
def value=(obj)
|
27
|
+
raise TypeError, 'value must be a string' unless obj.respond_to?(:to_str)
|
28
|
+
raise RangeError, 'value is max 75 characters' unless obj.size <= 75
|
29
|
+
|
30
|
+
@value = obj.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def description=(obj)
|
34
|
+
raise TypeError, 'description must be a Text Object' unless obj.is_a?(Text)
|
35
|
+
raise TypeError, 'description must be plain_text' unless obj.type == :plain_text
|
36
|
+
raise RangeError, 'description is max 75 characters' unless obj.text.size <= 75
|
37
|
+
|
38
|
+
@description = obj
|
39
|
+
end
|
40
|
+
|
41
|
+
def url=(obj)
|
42
|
+
raise TypeError, 'url must be a string' unless url.respond_to?(:to_str)
|
43
|
+
raise RangeError, 'url is max 3000 characters' unless url.size <= 3000
|
44
|
+
|
45
|
+
@url = url.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_h
|
49
|
+
{ text: text.to_h,
|
50
|
+
value: value,
|
51
|
+
description: description&.to_h,
|
52
|
+
url: url }.compact
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module CompositionObjects
|
6
|
+
class OptionGroup
|
7
|
+
attr_reader :label, :options
|
8
|
+
|
9
|
+
def self.[](hash)
|
10
|
+
new.tap do |object|
|
11
|
+
object.label = hash.fetch(:label)
|
12
|
+
hash[:options].each(&object.options.method(:<<))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@options = TypeRestrictedArray.new(Option)
|
18
|
+
end
|
19
|
+
|
20
|
+
def label=(obj)
|
21
|
+
raise TypeError, 'label must be a Text Object' unless obj.is_a?(Text)
|
22
|
+
raise RangeError, 'label is max 75 characters' unless obj.text.size <= 75
|
23
|
+
|
24
|
+
@label = obj
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
{ label: label.to_h,
|
29
|
+
options: options.map(&:to_h) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
module CompositionObjects
|
6
|
+
class Text
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :type, :text, :emoji, :verbatim
|
9
|
+
|
10
|
+
PLAINTEXT = :plain_text
|
11
|
+
MRKDWN = :mrkdwn
|
12
|
+
NEWLINE = "\n"
|
13
|
+
|
14
|
+
def self.[](hash)
|
15
|
+
new.tap do |object|
|
16
|
+
object.type = hash.keys.find { |key| [PLAINTEXT, MRKDWN].include?(key) }
|
17
|
+
raise ArgumentError, 'type must be `plain_text` or `mrkdwn`' unless object.type
|
18
|
+
|
19
|
+
object.text = hash[object.type]
|
20
|
+
object.emoji! if hash[:emoji]
|
21
|
+
object.verbatim! if hash[:verbatim]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def empty?
|
26
|
+
text&.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def emoji!
|
30
|
+
@emoji = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def verbatim!
|
34
|
+
@verbatim = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def type=(type)
|
38
|
+
unless [PLAINTEXT, MRKDWN].include?(type.to_sym)
|
39
|
+
raise ArgumentError, 'type must be `plain_text` or `mrkdwn`'
|
40
|
+
end
|
41
|
+
|
42
|
+
@type = type.to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
def text=(text)
|
46
|
+
text = text.join(NEWLINE) if text.is_a?(Array)
|
47
|
+
raise TypeError, 'text must be a string' unless text.respond_to?(:to_str)
|
48
|
+
|
49
|
+
@text = text.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_h
|
53
|
+
{ type: type,
|
54
|
+
text: text,
|
55
|
+
emoji: emoji,
|
56
|
+
verbatim: verbatim }.compact
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
attr_reader :action_id
|
7
|
+
|
8
|
+
def self.populate(hash, object)
|
9
|
+
object.action_id = hash[:action_id] if hash.key?(:action_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 action_id=(obj)
|
18
|
+
raise TypeError, 'action_id must be a string' unless action_id.respond_to?(:to_str)
|
19
|
+
raise RangeError, 'action_id must be max 255 characters' unless action_id.size <= 255
|
20
|
+
|
21
|
+
@action_id = obj.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def type
|
25
|
+
@type ||= self.class.name
|
26
|
+
.split('::')
|
27
|
+
.last.chomp('Element')
|
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
|
+
action_id: action_id }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class ButtonElement < Element
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :text, :style
|
9
|
+
attr_accessor :value
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
object.text = hash.fetch(:text)
|
13
|
+
object.action_id = hash.fetch(:action_id) if hash[:action_id]
|
14
|
+
object.style = hash.fetch(:style) if hash[:style]
|
15
|
+
object.value = hash.fetch(:value) if hash[:value]
|
16
|
+
|
17
|
+
super(hash, object)
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?
|
21
|
+
!@text.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def text=(obj)
|
25
|
+
raise TypeError, 'text must be a Text Object' unless obj.is_a?(CompositionObjects::Text)
|
26
|
+
|
27
|
+
@text = obj
|
28
|
+
end
|
29
|
+
|
30
|
+
def style=(obj)
|
31
|
+
unless %i( default primary danger ).include?(obj.to_sym)
|
32
|
+
raise ArgumentError, 'style may only be default, primary, or danger'
|
33
|
+
end
|
34
|
+
|
35
|
+
@style = obj.to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_h
|
39
|
+
super.merge(
|
40
|
+
text: text.to_h,
|
41
|
+
style: style,
|
42
|
+
value: value
|
43
|
+
).compact
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class ChannelsSelectElement < SelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :initial_channel, :response_url_enabled
|
9
|
+
attr_writer :initial_channel
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
object.initial_channel = hash[:initial_channel] if hash.key?(:initial_channel)
|
13
|
+
object.response_url_enabled! if hash.key?(:response_url_enabled)
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def response_url_enabled!
|
19
|
+
@response_url_enabled = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_h
|
23
|
+
super.merge(
|
24
|
+
initial_channel: initial_channel,
|
25
|
+
response_url_enabled: response_url_enabled
|
26
|
+
).compact
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class ConversationsSelectElement < SelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :initial_conversation, :response_url_enabled, :filter
|
9
|
+
attr_writer :initial_conversation
|
10
|
+
|
11
|
+
def self.populate(hash, object)
|
12
|
+
if hash.key?(:initial_conversation)
|
13
|
+
object.initial_conversation = hash[:initial_conversation]
|
14
|
+
end
|
15
|
+
object.response_url_enabled! if hash.key?(:response_url_enabled)
|
16
|
+
object.filter = hash[:filter] if hash.key?(:filter)
|
17
|
+
|
18
|
+
super(hash, object)
|
19
|
+
end
|
20
|
+
|
21
|
+
def response_url_enabled!
|
22
|
+
@response_url_enabled = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def filter=(obj)
|
26
|
+
unless obj.is_a?(CompositionObjects::Filter)
|
27
|
+
raise TypeError, 'confirm must be a Filter Object'
|
28
|
+
end
|
29
|
+
|
30
|
+
@filter = obj
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_h
|
34
|
+
super.merge(
|
35
|
+
initial_conversation: initial_conversation,
|
36
|
+
response_url_enabled: response_url_enabled,
|
37
|
+
filter: filter&.to_h
|
38
|
+
).compact
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class DatePickerElement < Element
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :initial_date, :placeholder, :confirm
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
object.placeholder = hash.fetch(:placeholder) if hash[:placeholder]
|
12
|
+
object.confirm = hash.fetch(:confirm) if hash[:confirm]
|
13
|
+
object.initial_date = hash.fetch(:initial_date) if hash[:initial_date]
|
14
|
+
|
15
|
+
super(hash, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
'datepicker'
|
20
|
+
end
|
21
|
+
|
22
|
+
def placeholder=(obj)
|
23
|
+
raise TypeError, 'placeholder must be a Text Object' unless obj.is_a?(CompositionObjects::Text)
|
24
|
+
raise TypeError, 'placeholder must be plain_text' unless obj.type == :plain_text
|
25
|
+
raise RangeError, 'placeholder is max 150 characters' unless obj.text.size <= 150
|
26
|
+
|
27
|
+
@placeholder = obj
|
28
|
+
end
|
29
|
+
|
30
|
+
def confirm=(obj)
|
31
|
+
unless obj.is_a?(CompositionObjects::ConfirmationDialog)
|
32
|
+
raise TypeError, 'confirm must be a ConfirmationDialog Object'
|
33
|
+
end
|
34
|
+
|
35
|
+
@confirm = obj
|
36
|
+
end
|
37
|
+
|
38
|
+
def initial_date=(date)
|
39
|
+
date = date.strftime('%Y-%m-%d') if date.is_a?(Time)
|
40
|
+
raise TypeError, 'initial_date must be a string' unless date.respond_to?(:to_str)
|
41
|
+
raise TypeError, 'initial_date must be YYYY-MM-DD' unless date.match?(/\d{4}-\d{2}-\d{2}/)
|
42
|
+
|
43
|
+
@initial_date = date.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_h
|
47
|
+
super.merge(
|
48
|
+
initial_date: initial_date,
|
49
|
+
placeholder: placeholder&.to_h,
|
50
|
+
confirm: confirm&.to_h
|
51
|
+
).compact
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module BlockKit
|
5
|
+
class Element
|
6
|
+
class ExternalSelectElement < SelectElement
|
7
|
+
using Refinements::HashCompact
|
8
|
+
attr_reader :initial_option, :min_query_length
|
9
|
+
|
10
|
+
def self.populate(hash, object)
|
11
|
+
object.initial_option = hash[:initial_option] if hash.key?(:initial_option)
|
12
|
+
object.min_query_length = hash[:min_query_length] if hash.key?(:min_query_length)
|
13
|
+
|
14
|
+
super(hash, object)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initial_option=(obj)
|
18
|
+
raise TypeError, 'initial_option must be a Option Object' unless obj.is_a?(CompositionObjects::Option)
|
19
|
+
|
20
|
+
@initial_option = obj
|
21
|
+
end
|
22
|
+
|
23
|
+
def min_query_length=(length)
|
24
|
+
raise TypeError, 'min_query_length must be an integer' unless length.respond_to?(:to_int)
|
25
|
+
|
26
|
+
@min_query_length = length.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
super.merge(
|
31
|
+
initial_option: initial_option&.to_h,
|
32
|
+
min_query_length: min_query_length || 3
|
33
|
+
).compact
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|