lookbook 1.1.1 → 1.2.1

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/lookbook/js/helpers/string.js +23 -1
  3. data/app/assets/lookbook/js/lookbook.js +0 -1
  4. data/app/components/lookbook/button/component.html.erb +2 -1
  5. data/app/components/lookbook/button/component.js +9 -0
  6. data/app/components/lookbook/display_options/editor/component.html.erb +13 -0
  7. data/app/components/lookbook/display_options/editor/component.rb +7 -0
  8. data/app/components/lookbook/display_options/field/component.css +33 -0
  9. data/app/components/lookbook/display_options/field/component.html.erb +8 -0
  10. data/app/components/lookbook/display_options/field/component.js +30 -0
  11. data/app/components/lookbook/display_options/field/component.rb +28 -0
  12. data/app/components/lookbook/inspector_panel/component.html.erb +1 -1
  13. data/app/components/lookbook/inspector_panel/component.rb +10 -11
  14. data/app/components/lookbook/params/editor/component.rb +6 -3
  15. data/app/components/lookbook/params/field/component.rb +1 -5
  16. data/app/components/lookbook/tab_panels/panel/component.html.erb +1 -1
  17. data/app/components/lookbook/tab_panels/panel/component.rb +1 -2
  18. data/app/components/lookbook/tabs/dropdown_tab/component.html.erb +1 -0
  19. data/app/components/lookbook/tabs/tab/component.html.erb +1 -0
  20. data/app/components/lookbook/viewport/component.html.erb +1 -1
  21. data/app/components/lookbook/viewport/component.rb +2 -1
  22. data/app/controllers/lookbook/previews_controller.rb +40 -29
  23. data/app/helpers/lookbook/preview_helper.rb +1 -1
  24. data/app/views/lookbook/previews/panels/_params.html.erb +1 -1
  25. data/app/views/lookbook/previews/panels/_preview.html.erb +9 -6
  26. data/app/views/lookbook/previews/show.html.erb +29 -11
  27. data/config/app.yml +36 -0
  28. data/config/hooks.yml +4 -0
  29. data/config/inputs.yml +48 -0
  30. data/config/panels.yml +30 -0
  31. data/config/routes.rb +1 -1
  32. data/config/tags.yml +29 -0
  33. data/lib/lookbook/engine.rb +40 -20
  34. data/lib/lookbook/markdown.rb +1 -11
  35. data/lib/lookbook/page.rb +1 -1
  36. data/lib/lookbook/params.rb +0 -7
  37. data/lib/lookbook/parser.rb +3 -10
  38. data/lib/lookbook/preview.rb +7 -3
  39. data/lib/lookbook/preview_example.rb +7 -3
  40. data/lib/lookbook/preview_group.rb +2 -2
  41. data/lib/lookbook/services/config_loader.rb +20 -0
  42. data/lib/lookbook/services/search_param_builder.rb +13 -0
  43. data/lib/lookbook/services/search_param_parser.rb +15 -0
  44. data/lib/lookbook/services/tags/key_value_tag_parser.rb +24 -0
  45. data/lib/lookbook/source_inspector.rb +10 -16
  46. data/lib/lookbook/stores/config_store.rb +80 -0
  47. data/lib/lookbook/stores/hook_store.rb +28 -0
  48. data/lib/lookbook/stores/input_store.rb +58 -0
  49. data/lib/lookbook/stores/panel_store.rb +141 -0
  50. data/lib/lookbook/stores/tag_store.rb +46 -0
  51. data/lib/lookbook/support/errors/config_error.rb +7 -0
  52. data/lib/lookbook/support/errors/lookbook_error.rb +21 -0
  53. data/lib/lookbook/support/errors/parser_error.rb +7 -0
  54. data/lib/lookbook/support/service.rb +7 -0
  55. data/lib/lookbook/support/store.rb +77 -0
  56. data/lib/lookbook/support/utils/attribute_utils.rb +9 -0
  57. data/lib/lookbook/support/utils/path_utils.rb +19 -0
  58. data/lib/lookbook/tags.rb +5 -14
  59. data/lib/lookbook/version.rb +1 -1
  60. data/lib/lookbook.rb +43 -12
  61. data/public/lookbook-assets/css/lookbook.css +33 -0
  62. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  63. data/public/lookbook-assets/js/lookbook.js +145 -4
  64. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  65. metadata +29 -6
  66. data/lib/lookbook/config.rb +0 -278
  67. data/lib/lookbook/hooks.rb +0 -21
  68. data/lib/lookbook/panels.rb +0 -25
  69. data/lib/lookbook/store.rb +0 -34
data/config/panels.yml ADDED
@@ -0,0 +1,30 @@
1
+ shared:
2
+ main:
3
+ - name: preview
4
+ partial: lookbook/previews/panels/preview
5
+ label: Preview
6
+ hotkey: v
7
+
8
+ - name: output
9
+ partial: lookbook/previews/panels/output
10
+ label: HTML
11
+ hotkey: h
12
+
13
+ drawer:
14
+ - name: source
15
+ partial: lookbook/previews/panels/source
16
+ label: Source
17
+ hotkey: s
18
+ copy: "->(data) { data.examples.map { |e| e.source }.join(\n) }"
19
+
20
+ - name: notes
21
+ partial: lookbook/previews/panels/notes
22
+ label: Notes
23
+ hotkey: n
24
+ disabled: ->(data) { data.examples.select { |e| e.notes.present? }.none? }
25
+
26
+ - name: params
27
+ partial: lookbook/previews/panels/params
28
+ label: Params
29
+ hotkey: p
30
+ disabled: ->(data) { data.preview.params.none? }
data/config/routes.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  Lookbook::Engine.routes.draw do
2
2
  if Lookbook::Engine.websocket?
3
- mount Lookbook::Engine.websocket => Lookbook.config.cable_mount_path, :as => :cable
3
+ mount Lookbook::Engine.websocket => "/cable", :as => :cable
4
4
  end
5
5
 
6
6
  root to: "application#index", as: :lookbook_home
data/config/tags.yml ADDED
@@ -0,0 +1,29 @@
1
+ shared:
2
+ hidden:
3
+ label: Hidden status
4
+ opts: {}
5
+
6
+ label:
7
+ label: Label
8
+ opts: {}
9
+
10
+ display:
11
+ label: Display
12
+ opts: {}
13
+
14
+ position:
15
+ label: Position
16
+ opts: {}
17
+
18
+ id:
19
+ label: Id
20
+ opts: {}
21
+
22
+ component:
23
+ label: Component
24
+ opts: {}
25
+
26
+ param:
27
+ label: Param
28
+ yard_parser: with_name
29
+ opts: {}
@@ -6,30 +6,33 @@ module Lookbook
6
6
  class Engine < Rails::Engine
7
7
  isolate_namespace Lookbook
8
8
 
9
- config.autoload_paths << File.expand_path(Lookbook::Engine.root.join("app/components"))
10
- config.lookbook = Lookbook.config
9
+ config.autoload_paths << File.expand_path(root.join("app/components"))
11
10
 
12
11
  initializer "lookbook.viewcomponent.config" do
13
- config.lookbook.preview_paths += config.view_component.preview_paths
14
- config.lookbook.preview_controller ||= config.view_component.preview_controller
12
+ Lookbook.config.preview_paths += config.view_component.preview_paths
13
+ Lookbook.config.preview_controller ||= config.view_component.preview_controller
15
14
 
16
- config.lookbook.components_path = config.view_component.view_component_path if config.view_component.view_component_path.present?
15
+ Lookbook.config.components_path = config.view_component.view_component_path if config.view_component.view_component_path.present?
17
16
 
18
- config.lookbook.listen_paths += config.lookbook.preview_paths
19
- config.lookbook.listen_paths << config.lookbook.components_path
17
+ Lookbook.config.listen_paths += Lookbook.config.preview_paths
18
+ Lookbook.config.listen_paths << Lookbook.config.components_path
20
19
  end
21
20
 
22
21
  initializer "lookbook.parser.tags" do
23
- Lookbook::Parser.define_tags(Lookbook.config.preview_tags)
22
+ Lookbook::Parser.define_tags(Engine.tags)
24
23
  end
25
24
 
26
25
  initializer "lookbook.assets.serve" do
27
26
  config.app_middleware.use(
28
27
  Rack::Static,
29
- urls: ["/lookbook-assets"], root: Lookbook::Engine.root.join("public").to_s
28
+ urls: ["/lookbook-assets"], root: root.join("public").to_s
30
29
  )
31
30
  end
32
31
 
32
+ config.before_configuration do
33
+ config.lookbook = Lookbook.config
34
+ end
35
+
33
36
  config.after_initialize do
34
37
  @preview_controller = Lookbook.config.preview_controller.constantize
35
38
  @preview_controller.include(Lookbook::PreviewController)
@@ -46,22 +49,22 @@ module Lookbook
46
49
  end
47
50
  else
48
51
  # Fallback for older Rails versions - don't start listeners if running in a rake task.
49
- unless Lookbook::Engine.prevent_listening?
52
+ unless prevent_listening?
50
53
  init_listeners
51
54
  end
52
55
  end
53
56
 
54
57
  parser.parse do
55
- Lookbook::Engine.run_hooks(:after_initialize)
58
+ run_hooks(:after_initialize)
56
59
  end
57
60
  end
58
61
 
59
62
  at_exit do
60
- if Lookbook::Engine.listeners.any?
63
+ if listeners.any?
61
64
  Lookbook.logger.debug "Stopping listeners"
62
- Lookbook::Engine.stop_listeners
65
+ stop_listeners
63
66
  end
64
- Lookbook::Engine.run_hooks(:before_exit)
67
+ run_hooks(:before_exit)
65
68
  end
66
69
 
67
70
  class << self
@@ -69,7 +72,7 @@ module Lookbook
69
72
  config = Lookbook.config
70
73
  return unless config.listen == true
71
74
 
72
- listen_paths = config.listen_paths.uniq
75
+ listen_paths = PathUtils.normalize_all(config.listen_paths)
73
76
  if listen_paths.any?
74
77
  preview_listener = Listen.to(*listen_paths,
75
78
  only: /\.(#{config.listen_extensions.join("|")})$/,
@@ -82,7 +85,7 @@ module Lookbook
82
85
  register_listener(preview_listener)
83
86
  end
84
87
 
85
- page_paths = config.page_paths.uniq
88
+ page_paths = PathUtils.normalize_all(config.page_paths)
86
89
  if page_paths.any?
87
90
  page_listener = Listen.to(*page_paths,
88
91
  only: /\.(html.*|md.*)$/,
@@ -117,7 +120,7 @@ module Lookbook
117
120
  end
118
121
 
119
122
  def websocket_mount_path
120
- "#{mounted_path}#{config.lookbook.cable_mount_path}".gsub("//", "/") if websocket?
123
+ "#{mounted_path}/cable".gsub("//", "/") if websocket?
121
124
  end
122
125
 
123
126
  def websocket?
@@ -125,11 +128,12 @@ module Lookbook
125
128
  end
126
129
 
127
130
  def mounted_path
128
- Lookbook::Engine.routes.find_script_name({})
131
+ routes.find_script_name({})
129
132
  end
130
133
 
131
134
  def parser
132
- @parser ||= Lookbook::Parser.new(config.lookbook.preview_paths)
135
+ preview_paths = PathUtils.normalize_all(Lookbook.config.preview_paths)
136
+ @parser ||= Lookbook::Parser.new(preview_paths)
133
137
  end
134
138
 
135
139
  def log_level
@@ -159,7 +163,7 @@ module Lookbook
159
163
  end
160
164
 
161
165
  def run_hooks(event_name, *args)
162
- config.lookbook.hooks[event_name].each do |hook|
166
+ hooks.for_event(event_name).each do |hook|
163
167
  hook.call(Lookbook, *args)
164
168
  end
165
169
  end
@@ -180,6 +184,22 @@ module Lookbook
180
184
  end
181
185
  end
182
186
 
187
+ def panels
188
+ @panels ||= PanelStore.init_from_config
189
+ end
190
+
191
+ def inputs
192
+ @inputs ||= InputStore.init_from_config
193
+ end
194
+
195
+ def tags
196
+ @tags ||= TagStore.init_from_config
197
+ end
198
+
199
+ def hooks
200
+ @hooks ||= HookStore.init_from_config
201
+ end
202
+
183
203
  attr_reader :preview_controller
184
204
  end
185
205
  end
@@ -2,19 +2,9 @@ require "redcarpet"
2
2
 
3
3
  module Lookbook
4
4
  class Markdown
5
- DEFAULT_OPTIONS = {
6
- tables: true,
7
- fenced_code_blocks: true,
8
- disable_indented_code_blocks: true,
9
- strikethrough: true,
10
- highlight: true,
11
- with_toc_data: true,
12
- lax_spacing: true
13
- }
14
-
15
5
  def self.render(text)
16
6
  Utils.strip_action_view_annotations!(text)
17
- markdown = Redcarpet::Markdown.new(Renderer, Lookbook.config.markdown_options)
7
+ markdown = Redcarpet::Markdown.new(Renderer, Lookbook.config.markdown_options.to_h)
18
8
  markdown.render(text).html_safe
19
9
  end
20
10
 
data/lib/lookbook/page.rb CHANGED
@@ -180,7 +180,7 @@ module Lookbook
180
180
  end
181
181
 
182
182
  def page_paths
183
- Lookbook.config.page_paths.select { |dir| Dir.exist? dir }
183
+ PathUtils.normalize_all(Lookbook.config.page_paths)
184
184
  end
185
185
 
186
186
  def section_path?(path)
@@ -117,13 +117,6 @@ module Lookbook
117
117
  end
118
118
  end
119
119
 
120
- def inputs
121
- @inputs ||= Lookbook.config.preview_param_inputs.map do |name, config|
122
- config = {partial: config} if config.is_a?(String)
123
- [name, {input_options: {}}.merge(config)]
124
- end.to_h
125
- end
126
-
127
120
  private
128
121
 
129
122
  def guess_input(value_type, default)
@@ -32,16 +32,9 @@ module Lookbook
32
32
  end
33
33
 
34
34
  class << self
35
- def define_tags(custom = {})
36
- YARD::Tags::Library.define_tag("Hidden status", :hidden)
37
- YARD::Tags::Library.define_tag("Label", :label)
38
- YARD::Tags::Library.define_tag("Display", :display)
39
- YARD::Tags::Library.define_tag("Position", :position)
40
- YARD::Tags::Library.define_tag("ID", :id)
41
- YARD::Tags::Library.define_tag("Component", :component)
42
- YARD::Tags::Library.define_tag("Param", :param, :with_name)
43
- custom.each do |name, opts|
44
- YARD::Tags::Library.define_tag(name.to_s.titleize, name)
35
+ def define_tags(tags = nil)
36
+ tags.to_h.each do |name, tag|
37
+ YARD::Tags::Library.define_tag(tag[:label], name, tag[:yard_parser])
45
38
  end
46
39
  end
47
40
  end
@@ -70,7 +70,7 @@ module Lookbook
70
70
  end
71
71
 
72
72
  def full_path
73
- base_path = Array(Lookbook.config.preview_paths).detect do |preview_path|
73
+ base_path = preview_paths.detect do |preview_path|
74
74
  Dir["#{preview_path}/#{rel_path}"].first
75
75
  end
76
76
  Pathname.new(Dir["#{base_path}/#{rel_path}"].first)
@@ -92,8 +92,8 @@ module Lookbook
92
92
  @preview.instance_variable_get(:@layout)
93
93
  end
94
94
 
95
- def display_params
96
- Lookbook.config.preview_display_params.deep_merge(@preview_inspector&.display_params)
95
+ def display_options
96
+ Lookbook.config.preview_display_options.deep_merge(@preview_inspector&.display_options)
97
97
  end
98
98
 
99
99
  def collapsible?
@@ -111,6 +111,10 @@ module Lookbook
111
111
  end
112
112
  end
113
113
 
114
+ def preview_paths
115
+ PathUtils.normalize_all(Lookbook.config.preview_paths)
116
+ end
117
+
114
118
  protected
115
119
 
116
120
  @preview_objects = nil
@@ -22,8 +22,8 @@ module Lookbook
22
22
  @example_inspector.label.presence || name.titleize
23
23
  end
24
24
 
25
- def display_params
26
- @preview.display_params.merge(@example_inspector.display_params)
25
+ def display_options
26
+ @preview.display_options.merge(@example_inspector.display_options)
27
27
  end
28
28
 
29
29
  def method_source
@@ -63,13 +63,17 @@ module Lookbook
63
63
 
64
64
  def full_template_path(template_path)
65
65
  template_path = strip_ext template_path
66
- base_path = Array(Lookbook.config.preview_paths).detect do |p|
66
+ base_path = preview_paths.detect do |p|
67
67
  Dir["#{p}/#{template_path}.html.*"].first
68
68
  end
69
69
  path = Dir["#{base_path}/#{template_path}.html.*"].first
70
70
  path ? Pathname.new(path) : nil
71
71
  end
72
72
 
73
+ def preview_paths
74
+ PathUtils.normalize_all(Lookbook.config.preview_paths)
75
+ end
76
+
73
77
  class << self
74
78
  def all
75
79
  Preview.all.map { |preview| preview.examples }.flatten
@@ -25,10 +25,10 @@ module Lookbook
25
25
  examples.map(&:params).flatten.uniq { |param| param[:name] }
26
26
  end
27
27
 
28
- def display_params
28
+ def display_options
29
29
  merged = {}
30
30
  examples.reverse.map do |example|
31
- merged.merge! example.display_params
31
+ merged.merge! example.display_options
32
32
  end
33
33
  merged
34
34
  end
@@ -0,0 +1,20 @@
1
+ module Lookbook
2
+ class ConfigLoader < Service
3
+ attr_reader :file, :env
4
+
5
+ def initialize(path, env: Rails.env)
6
+ @file = Engine.root.join(path)
7
+ @env = env.to_sym
8
+ end
9
+
10
+ def call
11
+ if file.exist?
12
+ config = YAML.load_file(file).deep_symbolize_keys
13
+ env_config = config[:shared].to_h.deep_merge(config[env].to_h)
14
+ Store.new(env_config)
15
+ else
16
+ raise ConfigError.new("Could not load configuration. No such file - #{file}")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Lookbook
2
+ class SearchParamBuilder < Service
3
+ attr_reader :data
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ end
8
+
9
+ def call
10
+ data.map { "#{_1}:#{_2}" }.join("|")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module Lookbook
2
+ class SearchParamParser < Service
3
+ attr_reader :param_value
4
+
5
+ def initialize(param_value)
6
+ @param_value = param_value.strip
7
+ end
8
+
9
+ def call
10
+ pairs_str = param_value.split("|")
11
+ pairs = pairs_str.map { [*_1.split(":").map(&:strip)] }
12
+ pairs.to_h.symbolize_keys
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module Lookbook
2
+ class KeyValueTagParser < Service
3
+ KEY_VALUE_REGEX = /^([^\s]+)\s+(.+)$/
4
+
5
+ attr_reader :text
6
+
7
+ def initialize(text)
8
+ @text = text.to_s
9
+ end
10
+
11
+ def call
12
+ text.strip.match(KEY_VALUE_REGEX) do |matches|
13
+ key = matches[1]
14
+ value = begin
15
+ YAML.safe_load(matches[2] || "~")
16
+ rescue ::Psych::SyntaxError => exception
17
+ raise ParserError.new("Invalid YAML in tag text '#{@text}'", scope: "key_value_tag.parser", original: exception)
18
+ end
19
+ return [key, value]
20
+ end
21
+ raise ParserError.new("Could not parse key:value pair from '#{@text}'", scope: "key_value_tag.parser")
22
+ end
23
+ end
24
+ end
@@ -52,22 +52,16 @@ module Lookbook
52
52
  end
53
53
  end
54
54
 
55
- def display_params
56
- return @display_params unless @display_params.nil?
57
- @display_params = {}.with_indifferent_access
58
- if code_object&.tags(:display).present?
59
- code_object.tags(:display).each do |tag|
60
- parts = tag.text.strip.match(/^([^\s]*)\s?(.*)$/)
61
- if parts.present?
62
- begin
63
- display_params[parts[1]] = YAML.safe_load(parts[2] || "~")
64
- rescue SyntaxError => err
65
- Lookbook.logger.error("\n👀 [Lookbook] Invalid JSON in @display tag.\n👀 [Lookbook] (#{err})\n")
66
- end
67
- end
68
- end
69
- end
70
- @display_params
55
+ def display_options
56
+ return @display_options unless @display_options.nil?
57
+ tags = code_object.tags(:display).to_a
58
+ pairs = tags.map { KeyValueTagParser.call(_1.text) }
59
+
60
+ # dynamic params set at the entity level are
61
+ # not (yet) supported so filter them out.
62
+ pairs.select! { |pair| !pair[1].is_a?(Array) && !pair[1].is_a?(Hash) }
63
+
64
+ pairs.to_h.symbolize_keys
71
65
  end
72
66
 
73
67
  def parameter_defaults
@@ -0,0 +1,80 @@
1
+ module Lookbook
2
+ class ConfigStore
3
+ CONFIG_FILE = "config/app.yml"
4
+
5
+ delegate_missing_to :store
6
+ attr_reader :store
7
+
8
+ def initialize(config = nil)
9
+ @store = Store.new(config, recursive: true)
10
+ end
11
+
12
+ def project_name=(name)
13
+ store[:project_name] = name == false ? nil : name
14
+ end
15
+
16
+ def page_paths=(paths = nil)
17
+ store[:page_paths] ||= []
18
+ store[:page_paths] += paths.to_a
19
+ end
20
+
21
+ def preview_paths=(paths = nil)
22
+ store[:preview_paths] ||= []
23
+ store[:preview_paths] += paths.to_a
24
+ end
25
+
26
+ def preview_display_params
27
+ Lookbook.logger.warn "The `preview_display_params` config option has been renamed to `preview_display_options` and will be removed in v2.0"
28
+ store[:preview_display_options]
29
+ end
30
+
31
+ def preview_display_params=(options)
32
+ Lookbook.logger.warn "The `preview_display_params` config option has been renamed to `preview_display_options` and will be removed in v2.0"
33
+ store[:preview_display_options] = options.to_h
34
+ end
35
+
36
+ def listen_extensions=(extensions = nil)
37
+ store[:listen_extensions] ||= []
38
+ store[:listen_extensions] += extensions.to_a
39
+ store[:listen_extensions].uniq!
40
+ end
41
+
42
+ def markdown_options=(options = nil)
43
+ store[:markdown_options] ||= {}
44
+ store[:markdown_options].merge!(options.to_h)
45
+ end
46
+
47
+ def ui_theme=(name)
48
+ name = name.to_s
49
+ if Theme.valid_theme?(name)
50
+ store[:ui_theme] = name
51
+ else
52
+ raise ConfigError.new("'#{name}' is not a valid Lookbook theme. ", scope: "app.config")
53
+ end
54
+ end
55
+
56
+ def ui_theme_overrides(&block)
57
+ if block
58
+ yield store[:ui_theme_overrides]
59
+ else
60
+ store[:ui_theme_overrides]
61
+ end
62
+ end
63
+
64
+ def runtime_parsing=(value)
65
+ Lookbook.logger.warn "The `runtime_parsing` config option has been deprecated and will be removed in v2.0"
66
+ end
67
+
68
+ def preview_srcdoc=(enable)
69
+ Lookbook.logger.warn "The `preview_srcdoc` config option is deprecated and will be removed in v2.0"
70
+ end
71
+
72
+ def self.init_from_config(env: Rails.env)
73
+ new(default_config(env: env))
74
+ end
75
+
76
+ def self.default_config(env: Rails.env)
77
+ ConfigLoader.call(CONFIG_FILE, env: env)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ module Lookbook
2
+ class HookStore
3
+ CONFIG_FILE = "config/hooks.yml"
4
+
5
+ attr_reader :store
6
+ delegate :to_h, to: :store
7
+
8
+ def initialize(config = nil)
9
+ @store = {}
10
+ end
11
+
12
+ def add_hook(event_name, callback)
13
+ for_event(event_name) << callback
14
+ end
15
+
16
+ def for_event(event_name)
17
+ store[event_name.to_sym] ||= []
18
+ end
19
+
20
+ def self.init_from_config
21
+ new(default_config)
22
+ end
23
+
24
+ def self.default_config
25
+ ConfigLoader.call(CONFIG_FILE)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,58 @@
1
+ module Lookbook
2
+ class InputStore
3
+ CONFIG_FILE = "config/inputs.yml"
4
+
5
+ DEFAULTS = {
6
+ # TODO
7
+ }
8
+
9
+ attr_reader :store
10
+ delegate :to_h, to: :store
11
+
12
+ def initialize(config = nil)
13
+ @store = {}
14
+
15
+ config.to_h.each do |name, opts|
16
+ add_input(name, opts[:partial], opts.except(:partial))
17
+ end
18
+ end
19
+
20
+ def add_input(input, *args)
21
+ store[input.to_sym] = build_config(input, *args)
22
+ end
23
+
24
+ def get_input(input)
25
+ store[input.to_sym]
26
+ end
27
+
28
+ def self.init_from_config
29
+ new(default_config)
30
+ end
31
+
32
+ def self.default_config
33
+ ConfigLoader.call(CONFIG_FILE)
34
+ end
35
+
36
+ protected
37
+
38
+ def build_config(name, *args)
39
+ partial = nil
40
+ opts = nil
41
+ if args.many? && args.last.is_a?(Hash)
42
+ partial = args.first
43
+ opts = args.last
44
+ elsif args.first.is_a?(String)
45
+ partial = args.first
46
+ end
47
+ if partial.present?
48
+ Store.new({
49
+ name: name.to_sym,
50
+ partial: partial,
51
+ opts: DEFAULTS.merge(opts.to_h)
52
+ })
53
+ else
54
+ raise ConfigError.new("inputs must define a partial path", scope: "inputs.config")
55
+ end
56
+ end
57
+ end
58
+ end