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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +4 -0
  6. data/README.md +62 -0
  7. data/Rakefile +6 -0
  8. data/bin/console +27 -0
  9. data/bin/setup +8 -0
  10. data/examples/slack_template_00.rb +46 -0
  11. data/examples/slack_template_01.rb +22 -0
  12. data/examples/slack_template_02.rb +28 -0
  13. data/examples/slack_template_03.rb +57 -0
  14. data/examples/slack_template_04.rb +29 -0
  15. data/examples/slack_template_05.rb +12 -0
  16. data/examples/slack_template_06.rb +53 -0
  17. data/examples/slack_template_07.rb +74 -0
  18. data/examples/slack_template_08.rb +77 -0
  19. data/examples/slack_template_09.rb +53 -0
  20. data/lib/slack-block-kit.rb +1 -0
  21. data/lib/slack/block_kit.rb +38 -0
  22. data/lib/slack/block_kit/block.rb +41 -0
  23. data/lib/slack/block_kit/block/actions_block.rb +35 -0
  24. data/lib/slack/block_kit/block/context_block.rb +30 -0
  25. data/lib/slack/block_kit/block/divider_block.rb +17 -0
  26. data/lib/slack/block_kit/block/image_block.rb +44 -0
  27. data/lib/slack/block_kit/block/section_block.rb +55 -0
  28. data/lib/slack/block_kit/composition_objects/confirmation_dialog.rb +59 -0
  29. data/lib/slack/block_kit/composition_objects/filter.rb +38 -0
  30. data/lib/slack/block_kit/composition_objects/option.rb +57 -0
  31. data/lib/slack/block_kit/composition_objects/option_group.rb +34 -0
  32. data/lib/slack/block_kit/composition_objects/text.rb +61 -0
  33. data/lib/slack/block_kit/element.rb +41 -0
  34. data/lib/slack/block_kit/element/button_element.rb +48 -0
  35. data/lib/slack/block_kit/element/channels_select_element.rb +31 -0
  36. data/lib/slack/block_kit/element/conversations_select_element.rb +43 -0
  37. data/lib/slack/block_kit/element/date_picker_element.rb +56 -0
  38. data/lib/slack/block_kit/element/external_select_element.rb +38 -0
  39. data/lib/slack/block_kit/element/image_element.rb +26 -0
  40. data/lib/slack/block_kit/element/multi_channels_select_element.rb +38 -0
  41. data/lib/slack/block_kit/element/multi_conversations_select_element.rb +38 -0
  42. data/lib/slack/block_kit/element/multi_external_select_element.rb +38 -0
  43. data/lib/slack/block_kit/element/multi_static_select_element.rb +38 -0
  44. data/lib/slack/block_kit/element/multi_users_select_element.rb +39 -0
  45. data/lib/slack/block_kit/element/overflow_element.rb +42 -0
  46. data/lib/slack/block_kit/element/select_element.rb +45 -0
  47. data/lib/slack/block_kit/element/static_select_element.rb +46 -0
  48. data/lib/slack/block_kit/element/users_select_element.rb +24 -0
  49. data/lib/slack/block_kit/execution_context.rb +64 -0
  50. data/lib/slack/block_kit/refinements/hash_compact.rb +15 -0
  51. data/lib/slack/block_kit/type_restricted_array.rb +21 -0
  52. data/lib/slack/block_kit/version.rb +5 -0
  53. data/slack-block-kit.gemspec +29 -0
  54. metadata +166 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class ImageElement < Element
7
+ using Refinements::HashCompact
8
+ attr_accessor :image_url, :alt_text
9
+
10
+ def self.populate(hash, object)
11
+ object.image_url = hash.fetch(:image_url)
12
+ object.alt_text = hash.fetch(:alt_text)
13
+
14
+ super(hash, object)
15
+ end
16
+
17
+ def to_h
18
+ super.merge(
19
+ image_url: image_url,
20
+ alt_text: alt_text
21
+ ).compact
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class MultiChannelsSelectElement < ChannelsSelectElement
7
+ using Refinements::HashCompact
8
+ undef_method :initial_channel=
9
+ attr_reader :initial_channels, :max_selected_items
10
+
11
+ def self.populate(hash, object)
12
+ hash[:initial_channels].each(&object.initial_channels.method(:<<)) if hash.key?(:initial_channels)
13
+ object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
14
+
15
+ super(hash, object)
16
+ end
17
+
18
+ def initialize
19
+ super
20
+ @initial_channels = []
21
+ end
22
+
23
+ def max_selected_items=(num)
24
+ raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
25
+
26
+ @max_selected_items = num.to_i
27
+ end
28
+
29
+ def to_h
30
+ super.merge(
31
+ initial_channels: initial_channels&.to_h,
32
+ max_selected_items: max_selected_items || 1
33
+ ).compact
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class MultiConversationsSelectElement < ConversationsSelectElement
7
+ using Refinements::HashCompact
8
+ undef_method :initial_conversation=
9
+ attr_reader :initial_conversations, :max_selected_items
10
+
11
+ def self.populate(hash, object)
12
+ hash[:initial_conversations].each(&object.initial_conversations.method(:<<)) if hash.key?(:initial_conversations)
13
+ object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
14
+
15
+ super(hash, object)
16
+ end
17
+
18
+ def initialize
19
+ super
20
+ @initial_conversations = []
21
+ end
22
+
23
+ def max_selected_items=(num)
24
+ raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
25
+
26
+ @max_selected_items = num.to_i
27
+ end
28
+
29
+ def to_h
30
+ super.merge(
31
+ initial_conversations: initial_conversations&.to_h,
32
+ max_selected_items: max_selected_items || 1
33
+ ).compact
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class MultiExternalSelectElement < ExternalSelectElement
7
+ using Refinements::HashCompact
8
+ undef_method :initial_option=
9
+ attr_reader :initial_options, :max_selected_items
10
+
11
+ def self.populate(hash, object)
12
+ hash[:initial_options].each(&object.initial_options.method(:<<)) if hash.key?(:initial_options)
13
+ object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
14
+
15
+ super(hash, object)
16
+ end
17
+
18
+ def initialize
19
+ super
20
+ @initial_options = TypeRestrictedArray.new(CompositionObjects::Option)
21
+ end
22
+
23
+ def max_selected_items=(num)
24
+ raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
25
+
26
+ @max_selected_items = num.to_i
27
+ end
28
+
29
+ def to_h
30
+ super.merge(
31
+ initial_options: initial_options&.to_h,
32
+ max_selected_items: max_selected_items || 1
33
+ ).compact
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class MultiStaticSelectElement < StaticSelectElement
7
+ using Refinements::HashCompact
8
+ undef_method :initial_option=
9
+ attr_reader :initial_options, :max_selected_items
10
+
11
+ def self.populate(hash, object)
12
+ hash[:initial_options].each(&object.initial_options.method(:<<)) if hash.key?(:initial_options)
13
+ object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
14
+
15
+ super(hash, object)
16
+ end
17
+
18
+ def initialize
19
+ super
20
+ @initial_options = TypeRestrictedArray.new(CompositionObjects::Option)
21
+ end
22
+
23
+ def max_selected_items=(num)
24
+ raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
25
+
26
+ @max_selected_items = num.to_i
27
+ end
28
+
29
+ def to_h
30
+ super.merge(
31
+ initial_options: initial_options&.to_h,
32
+ max_selected_items: max_selected_items || 1
33
+ ).compact
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class MultiUsersSelectElement < UsersSelectElement
7
+ using Refinements::HashCompact
8
+
9
+ undef_method :initial_user=
10
+ attr_reader :initial_users, :max_selected_items
11
+
12
+ def self.populate(hash, object)
13
+ hash[:initial_users].each(&object.initial_users.method(:<<)) if hash.key?(:initial_users)
14
+ object.max_selected_items = hash[:max_selected_items] if hash.key?(:max_selected_items)
15
+
16
+ super(hash, object)
17
+ end
18
+
19
+ def initialize
20
+ super
21
+ @initial_users = []
22
+ end
23
+
24
+ def max_selected_items=(num)
25
+ raise TypeError, 'max_selected_items must be an integer' unless num.respond_to?(:to_int)
26
+
27
+ @max_selected_items = num.to_i
28
+ end
29
+
30
+ def to_h
31
+ super.merge(
32
+ initial_users: initial_users&.to_h,
33
+ max_selected_items: max_selected_items || 1
34
+ ).compact
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class OverflowElement < Element
7
+ using Refinements::HashCompact
8
+ attr_reader :options, :confirm
9
+
10
+ def self.populate(hash, object)
11
+ hash[:options].each(&object.options.method(:<<)) if hash.key?(:options)
12
+ object.confirm = hash.fetch(:confirm) if hash[:confirm]
13
+
14
+ super(hash, object)
15
+ end
16
+
17
+ def initialize
18
+ @options = TypeRestrictedArray.new(CompositionObjects::Option)
19
+ end
20
+
21
+ def valid?
22
+ (2..5).include?(options.size)
23
+ end
24
+
25
+ def confirm=(obj)
26
+ unless obj.is_a?(CompositionObjects::ConfirmationDialog)
27
+ raise TypeError, 'confirm must be a ConfirmationDialog Object'
28
+ end
29
+
30
+ @confirm = obj
31
+ end
32
+
33
+ def to_h
34
+ super.merge(
35
+ options: options.map(&:to_h),
36
+ confirm: confirm&.to_h
37
+ ).compact
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class SelectElement < Element
7
+ attr_reader :placeholder, :confirm
8
+
9
+ def self.populate(hash, object)
10
+ object.placeholder = hash.fetch(:placeholder)
11
+ object.confirm = hash[:confirm] if hash.key?(:confirm)
12
+
13
+ super(hash, object)
14
+ end
15
+
16
+ def valid?
17
+ !(@placeholder.nil? || @placeholder.empty?)
18
+ end
19
+
20
+ def placeholder=(obj)
21
+ raise TypeError, 'placeholder must be a Text Object' unless obj.is_a?(CompositionObjects::Text)
22
+ raise TypeError, 'placeholder must be plain_text' unless obj.type == :plain_text
23
+ raise RangeError, 'placeholder is max 150 characters' unless obj.text.size <= 150
24
+
25
+ @placeholder = obj
26
+ end
27
+
28
+ def confirm=(obj)
29
+ unless obj.is_a?(CompositionObjects::ConfirmationDialog)
30
+ raise TypeError, 'confirm must be a ConfirmationDialog Object'
31
+ end
32
+
33
+ @confirm = obj
34
+ end
35
+
36
+ def to_h
37
+ super.merge(
38
+ placeholder: placeholder.to_h,
39
+ confirm: confirm&.to_h
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class StaticSelectElement < SelectElement
7
+ using Refinements::HashCompact
8
+ attr_reader :options, :option_groups, :initial_option
9
+
10
+ def self.populate(hash, object)
11
+ hash[:options].each(&object.options.method(:<<)) if hash.key?(:options)
12
+ hash[:option_groups].each(&object.option_groups.method(:<<)) if hash.key?(:option_groups)
13
+ object.initial_option = hash[:initial_option] if hash.key?(:initial_option)
14
+
15
+ super(hash, object)
16
+ end
17
+
18
+ def initialize
19
+ @options = TypeRestrictedArray.new(CompositionObjects::Option)
20
+ @option_groups = TypeRestrictedArray.new(CompositionObjects::OptionGroup)
21
+ end
22
+
23
+ # Either options or option_groups must exist and be non-empty.
24
+ def valid?
25
+ if @options.nil? || @options.empty? then !@option_groups.empty?
26
+ else !@options&.empty?
27
+ end
28
+ end
29
+
30
+ def initial_option=(obj)
31
+ raise TypeError, 'text must be a Option Object' unless obj.is_a?(CompositionObjects::Option)
32
+
33
+ @initial_option = obj
34
+ end
35
+
36
+ def to_h
37
+ super.merge(
38
+ options: options.map(&:to_h),
39
+ option_groups: option_groups.map(&:to_h),
40
+ initial_option: initial_option&.to_h
41
+ ).compact
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ class Element
6
+ class UsersSelectElement < SelectElement
7
+ using Refinements::HashCompact
8
+ attr_accessor :initial_user
9
+
10
+ def self.populate(hash, object)
11
+ object.initial_user = hash[:initial_user] if hash.key?(:initial_user)
12
+
13
+ super(hash, object)
14
+ end
15
+
16
+ def to_h
17
+ super.merge(
18
+ initial_user: initial_user
19
+ ).compact
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ module BlockKit
5
+ # TO USE:
6
+ # include Slack::Messages::Blocks::ExecutionContext
7
+ # data = [ SectionBlock[text: Text[mrkdwn: 'wheeee']] ]
8
+ # Slack::Messages::Blocks::ExecutionContext.test(data)
9
+ # => {
10
+ # "blocks": [
11
+ # {
12
+ # "type": "section",
13
+ # "text": {
14
+ # "type": "mrkdwn",
15
+ # "text": "wheeee"
16
+ # }
17
+ # }
18
+ # ]
19
+ # }
20
+ # This can be copied and pasted into https://api.slack.com/tools/block-kit-builder
21
+ module ExecutionContext
22
+ ActionsBlock = Block::ActionsBlock
23
+ ContextBlock = Block::ContextBlock
24
+ DividerBlock = Block::DividerBlock
25
+ ImageBlock = Block::ImageBlock
26
+ SectionBlock = Block::SectionBlock
27
+
28
+ def DividerBlock
29
+ DividerBlock[]
30
+ end
31
+
32
+ ConfirmationDialog = CompositionObjects::ConfirmationDialog
33
+ Filter = CompositionObjects::Filter
34
+ Option = CompositionObjects::Option
35
+ OptionGroup = CompositionObjects::OptionGroup
36
+ Text = CompositionObjects::Text
37
+
38
+ ButtonElement = Element::ButtonElement
39
+ DatePickerElement = Element::DatePickerElement
40
+ ImageElement = Element::ImageElement
41
+ OverflowElement = Element::OverflowElement
42
+
43
+ ConversationsSelectElement = Element::ConversationsSelectElement
44
+ ChannelsSelectElement = Element::ChannelsSelectElement
45
+ ExternalSelectElement = Element::ExternalSelectElement
46
+ StaticSelectElement = Element::StaticSelectElement
47
+ UsersSelectElement = Element::UsersSelectElement
48
+
49
+ MultiConversationsSelectElement = Element::MultiConversationsSelectElement
50
+ MultiChannelsSelectElement = Element::MultiChannelsSelectElement
51
+ MultiExternalSelectElement = Element::MultiExternalSelectElement
52
+ MultiStaticSelectElement = Element::MultiStaticSelectElement
53
+ MultiUsersSelectElement = Element::MultiUsersSelectElement
54
+
55
+ Bold = proc { |string| "*#{string}*" }
56
+ Italic = proc { |string| "_#{string}_" }
57
+ Strike = proc { |string| "~#{string}~" }
58
+ Code = proc { |string| "`#{string}`" }
59
+ Link = proc { |link, label = nil| label.nil? || label.empty? ? link : "<#{link}|#{label}>" }
60
+ Emoji = proc { |string| ":#{string}:" }
61
+ CodeBlock = proc { |&block| [ '```', yield, '```' ].join(Text::NEWLINE) }
62
+ end
63
+ end
64
+ end