action_component 0.1.0 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 743d176be9df1da38d3b0aa1b4609505ea8de03a
4
- data.tar.gz: 7be1460ea0d7b0f68e58bb90a70ec78ff8ee6013
3
+ metadata.gz: 255003a7f08bfb6d27d4994f5bcbd598ed1c12ad
4
+ data.tar.gz: 096cf23179c4f7c49f6168d484b6af4f4396ca97
5
5
  SHA512:
6
- metadata.gz: 92ba9a92079dc33beaac95607f98dcad316b559540dfcc54be48cec5a7bb3f4759cf283fd8af3292fcc8e914777dfa77b36fd9be0ce397432d64ea5e565dba1c
7
- data.tar.gz: 7e540ab4fc1fd22440286c3e1bee0293e1f069f7c2f59fe03afb90851e738d9148202374260d0dc661dfc1596bde57625b3fb7cc110abf51699a5026b7b9d685
6
+ metadata.gz: 9c676138c609aec84ff3b027377d086e1e1d9d60b8b7a88f82a614927eed75878d5321c0269a2391dc90cda53bb1a85576c707016ac725e40849add50b2e002b
7
+ data.tar.gz: 9c3a1f61257e06e780412d2d319c83a55bb82285e2e70ddf59522a3c50058592fefbcf0eccc10b3ab74dc538de2aa53af6f97d71758cea7af574352038ada8d6
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
1
  *.gem
2
+ vendor/
3
+ .bundle/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,83 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ action_component (0.1.1)
5
+ actionpack (>= 4)
6
+ activesupport (>= 4)
7
+ railties (>= 4)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ actionpack (5.0.0.1)
13
+ actionview (= 5.0.0.1)
14
+ activesupport (= 5.0.0.1)
15
+ rack (~> 2.0)
16
+ rack-test (~> 0.6.3)
17
+ rails-dom-testing (~> 2.0)
18
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
19
+ actionview (5.0.0.1)
20
+ activesupport (= 5.0.0.1)
21
+ builder (~> 3.1)
22
+ erubis (~> 2.7.0)
23
+ rails-dom-testing (~> 2.0)
24
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
25
+ activesupport (5.0.0.1)
26
+ concurrent-ruby (~> 1.0, >= 1.0.2)
27
+ i18n (~> 0.7)
28
+ minitest (~> 5.1)
29
+ tzinfo (~> 1.1)
30
+ builder (3.2.2)
31
+ concurrent-ruby (1.0.2)
32
+ diff-lcs (1.2.5)
33
+ erubis (2.7.0)
34
+ i18n (0.7.0)
35
+ loofah (2.0.3)
36
+ nokogiri (>= 1.5.9)
37
+ method_source (0.8.2)
38
+ mini_portile2 (2.1.0)
39
+ minitest (5.9.1)
40
+ nokogiri (1.6.8.1)
41
+ mini_portile2 (~> 2.1.0)
42
+ rack (2.0.1)
43
+ rack-test (0.6.3)
44
+ rack (>= 1.0)
45
+ rails-dom-testing (2.0.1)
46
+ activesupport (>= 4.2.0, < 6.0)
47
+ nokogiri (~> 1.6.0)
48
+ rails-html-sanitizer (1.0.3)
49
+ loofah (~> 2.0)
50
+ railties (5.0.0.1)
51
+ actionpack (= 5.0.0.1)
52
+ activesupport (= 5.0.0.1)
53
+ method_source
54
+ rake (>= 0.8.7)
55
+ thor (>= 0.18.1, < 2.0)
56
+ rake (11.3.0)
57
+ rspec (3.5.0)
58
+ rspec-core (~> 3.5.0)
59
+ rspec-expectations (~> 3.5.0)
60
+ rspec-mocks (~> 3.5.0)
61
+ rspec-core (3.5.4)
62
+ rspec-support (~> 3.5.0)
63
+ rspec-expectations (3.5.0)
64
+ diff-lcs (>= 1.2.0, < 2.0)
65
+ rspec-support (~> 3.5.0)
66
+ rspec-mocks (3.5.0)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.5.0)
69
+ rspec-support (3.5.0)
70
+ thor (0.19.3)
71
+ thread_safe (0.3.5)
72
+ tzinfo (1.2.2)
73
+ thread_safe (~> 0.1)
74
+
75
+ PLATFORMS
76
+ ruby
77
+
78
+ DEPENDENCIES
79
+ action_component!
80
+ rspec
81
+
82
+ BUNDLED WITH
83
+ 1.12.5
data/README.md CHANGED
@@ -2,7 +2,20 @@
2
2
 
3
3
  A React-style component system for Ruby on Rails.
4
4
 
5
- This gem should be considered "alpha" as it currently has no tests.
5
+ As your application gets bigger, you'll find you have components which are common to multiple pages.
6
+ The normal Rails way is to use a `render :partial`, but you might have some logic and/or database
7
+ setup you want to do for this partial. Short of putting them in every controller that uses the
8
+ component, or even worse, putting them in the view, there's no elegant solution.
9
+
10
+ Enter ActionComponent. Encapsulate a component's setup logic and view in the same class, and
11
+ render the component either from an existing Rails view, or straight from the controller.
12
+
13
+ While you can use Rails views to render your component's HTML, you can also use the JSX-like language
14
+ directly in your component's Ruby code.
15
+
16
+ ## Installation
17
+
18
+ Add `gem "action_component"` to your Gemfile and run `bundle`. Done.
6
19
 
7
20
  ## Examples
8
21
 
@@ -65,9 +78,13 @@ end
65
78
  # app/components/post_component.rb
66
79
 
67
80
  class PostComponent < ActionComponent::Base
81
+ # You can specify which variables must be passed to this component and their
82
+ # types (but only if you want to; by default it accepts everything.)
83
+ required post: Post
84
+
68
85
  def view
69
86
  div(class: 'post') do
70
- h2(@post.title)
87
+ h2 @post.title
71
88
 
72
89
  component AuthorComponent, author: @post.author
73
90
 
@@ -77,6 +94,11 @@ class PostComponent < ActionComponent::Base
77
94
  end
78
95
  ```
79
96
 
97
+ ## More documentation to come
98
+
99
+ ActionComponent is new. It works just fine, but at the moment if you need more information than is given above,
100
+ please dive into the (very small) codebase to learn more.
101
+
80
102
  ## Contributing
81
103
 
82
104
  Pull requests welcome! If you're thinking of contributing a new feature, or
@@ -15,6 +15,7 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.add_dependency "actionpack", ">= 4"
17
17
  s.add_dependency "activesupport", ">= 4"
18
+ s.add_dependency "railties", ">= 4"
18
19
 
19
20
  s.add_development_dependency "rspec"
20
21
 
@@ -1,8 +1,12 @@
1
1
  module ActionComponent
2
2
  end
3
3
 
4
+ require 'action_component/version'
5
+
4
6
  require 'action_component/action_controller_rendering'
5
7
  require 'action_component/action_view_rendering'
8
+ require 'action_component/constraints'
9
+ require 'action_component/elements'
10
+
6
11
  require 'action_component/base'
7
12
  require 'action_component/railtie'
8
- require 'action_component/version'
@@ -1,41 +1,26 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
1
3
  module ActionComponent
2
4
  RenderError = Class.new(StandardError)
3
-
4
- ELEMENTS = %w(
5
- html head title base link meta style
6
- script noscript
7
- body section nav article aside h1 h2 h3 h4 h5 h6 hgroup header footer address
8
- p hr br pre blockquote ol ul li dl dt dd figure figcaption div
9
- a em strong small s cite q dfn abbr time code var samp kbd sub sup i b u mark rt rp bdi bdo span
10
- ins del
11
- img iframe embed object param video audio source track canvas map area
12
- table caption colgroup col tbody thead tfoot tr td th
13
- form fieldset legend label input button select datalist optgroup option textarea keygen output progress meter
14
- details summary command menu
15
- )
5
+ ConstraintError = Class.new(StandardError)
6
+ ViewMissingError = Class.new(StandardError)
16
7
 
17
8
  class Base
18
- delegate :concat, to: :@_view
19
-
20
- def self.define_tags(*element_names)
21
- element_names.each do |element_name|
22
- define_method(element_name) do |*args, &block|
23
- element(element_name, *args, &block)
24
- end
25
-
26
- private element_name
27
- end
28
- end
9
+ include ActionComponent::Constraints
10
+ include ActionComponent::Elements
29
11
 
30
- define_tags *ActionComponent::ELEMENTS
12
+ delegate :concat, to: :@_view
31
13
 
32
14
  def self.render(view, opts = {})
33
15
  component = new(view, opts)
34
16
  component.load
35
17
  component.view
18
+ nil
36
19
  end
37
20
 
38
21
  def initialize(view, opts = {})
22
+ check_constraints!(opts)
23
+
39
24
  opts.each do |key, value|
40
25
  instance_variable_set("@#{key}", value)
41
26
  end
@@ -47,7 +32,7 @@ module ActionComponent
47
32
  end
48
33
 
49
34
  def view
50
- raise "#{self.class.name} must define a view method to be a valid component"
35
+ raise ActionComponent::ViewMissingError, "#{self.class.name} must define a view method to be a valid component"
51
36
  end
52
37
 
53
38
  private
@@ -65,43 +50,9 @@ module ActionComponent
65
50
  end
66
51
 
67
52
  def component(component, opts = {})
68
- self.class.render(@_view, opts)
53
+ component.render(@_view, opts)
69
54
  end
70
55
 
71
56
  alias_method :render_component, :component
72
-
73
- def text(content)
74
- @_view.concat content
75
- end
76
-
77
- alias_method :text_node, :text
78
- alias_method :insert, :text
79
-
80
- def doctype(text = "html")
81
- @_view.concat("<!doctype #{h(text)}>".html_safe)
82
- end
83
-
84
- def element(name, first = nil, second = nil, &block)
85
- if first.is_a?(Hash)
86
- opts = first
87
- else
88
- opts = second
89
- text = first
90
- end
91
-
92
- output = if text && block
93
- raise ActionComponent::RenderError, "An element cannot have both text and a block supplied; choose one or the other"
94
- elsif text
95
- @_view.content_tag name, text, opts
96
- elsif block
97
- @_view.content_tag name, opts, &block
98
- else
99
- @_view.tag name, opts
100
- end
101
-
102
- @_view.concat(output)
103
-
104
- nil
105
- end
106
57
  end
107
58
  end
@@ -0,0 +1,52 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/class/attribute'
3
+
4
+ module ActionComponent
5
+ module Constraints
6
+ extend ActiveSupport::Concern
7
+
8
+ Constraint = Struct.new(:name, :class_constraint, :required?)
9
+
10
+ included do
11
+ class_attribute :initializer_constraints
12
+
13
+ self.initializer_constraints = []
14
+ end
15
+
16
+ class_methods do
17
+ def required(*fields)
18
+ fields.each do |field|
19
+ if field.is_a?(Hash)
20
+ field.each do |name, class_constraint|
21
+ self.initializer_constraints += [Constraint.new(name, class_constraint, true)]
22
+ end
23
+ else
24
+ self.initializer_constraints += [Constraint.new(field, nil, true)]
25
+ end
26
+ end
27
+ end
28
+
29
+ def optional(fields)
30
+ raise ActionComponent::ConstraintError, "optional can only take a hash of field names and classes" unless fields.is_a?(Hash)
31
+
32
+ fields.each do |name, class_constraint|
33
+ self.initializer_constraints += [Constraint.new(name, class_constraint, false)]
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def check_constraints!(opts)
41
+ initializer_constraints.each do |constraint|
42
+ if constraint.required? && !opts.member?(constraint.name)
43
+ raise ActionComponent::ConstraintError, "#{constraint.name} is required for component #{self.class.name}"
44
+ end
45
+
46
+ if constraint.class_constraint && opts.member?(constraint.name) && !opts[constraint.name].is_a?(constraint.class_constraint)
47
+ raise ActionComponent::ConstraintError, "#{constraint.name} must be a #{constraint.class_constraint.name}"
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,74 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/string/output_safety'
3
+
4
+ module ActionComponent
5
+ module Elements
6
+ extend ActiveSupport::Concern
7
+ include ERB::Util
8
+
9
+ ELEMENTS = %w(
10
+ html head title base link meta style
11
+ script noscript
12
+ body section nav article aside h1 h2 h3 h4 h5 h6 hgroup header footer address
13
+ p hr br pre blockquote ol ul li dl dt dd figure figcaption div
14
+ a em strong small s cite q dfn abbr time code var samp kbd sub sup i b u mark rt rp bdi bdo span
15
+ ins del
16
+ img iframe embed object param video audio source track canvas map area
17
+ table caption colgroup col tbody thead tfoot tr td th
18
+ form fieldset legend label input button select datalist optgroup option textarea keygen output progress meter
19
+ details summary command menu
20
+ )
21
+
22
+ included do
23
+ define_tags *ELEMENTS
24
+
25
+ alias_method :text_node, :text
26
+ alias_method :insert, :text
27
+ end
28
+
29
+ class_methods do
30
+ def define_tags(*element_names)
31
+ element_names.each do |element_name|
32
+ define_method(element_name) do |*args, &block|
33
+ element(element_name, *args, &block)
34
+ end
35
+
36
+ private element_name
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def text(content)
44
+ @_view.concat content
45
+ end
46
+
47
+ def doctype(text = "html")
48
+ @_view.concat("<!doctype #{h(text)}>".html_safe)
49
+ end
50
+
51
+ def element(name, first = nil, second = nil, &block)
52
+ if first.is_a?(Hash)
53
+ opts = first
54
+ else
55
+ opts = second
56
+ text = first
57
+ end
58
+
59
+ output = if text && block
60
+ raise ActionComponent::RenderError, "An element cannot have both text and a block supplied; choose one or the other"
61
+ elsif text
62
+ @_view.content_tag name, text, opts
63
+ elsif block
64
+ @_view.content_tag name, opts, &block
65
+ else
66
+ @_view.tag name, opts
67
+ end
68
+
69
+ @_view.concat(output)
70
+
71
+ nil
72
+ end
73
+ end
74
+ end
@@ -1,3 +1,5 @@
1
+ require 'rails/railtie'
2
+
1
3
  module ActionComponent
2
4
  class Railtie < Rails::Railtie
3
5
  initializer "action_component.add_to_action_controller" do
@@ -1,3 +1,3 @@
1
1
  module ActionComponent
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActionComponent::Base do
4
+ let(:view) { double }
5
+ let(:opts) { {option: 'value'} }
6
+
7
+ subject { ActionComponent::Base.new(view, opts) }
8
+
9
+ describe "::render" do
10
+ it "makes a new component, then calls load and view, returning nil" do
11
+ component = instance_double(ActionComponent::Base)
12
+ expect(component).to receive(:load).ordered
13
+ expect(component).to receive(:view).ordered
14
+
15
+ expect(ActionComponent::Base).to receive(:new)
16
+ .with(view, {option: 'value'})
17
+ .and_return(component)
18
+
19
+ result = ActionComponent::Base.render(view, option: 'value')
20
+ expect(result).to be nil
21
+ end
22
+ end
23
+
24
+ describe "#load" do
25
+ it "does nothing" do
26
+ expect(subject.load).to be nil
27
+ end
28
+ end
29
+
30
+ describe "#view" do
31
+ it "raises" do
32
+ expect { subject.view }.to raise_error ActionComponent::ViewMissingError
33
+ end
34
+ end
35
+
36
+ describe "private methods used by subclasses" do
37
+ class AuthorComponent < ActionComponent::Base
38
+ def view
39
+ div @author
40
+ end
41
+ end
42
+
43
+ class TestComponent < ActionComponent::Base
44
+ def view
45
+ div(class: "post") do
46
+ h2 @post.title
47
+
48
+ div datetime_formatter(@post.posted_at), class: "datetime"
49
+
50
+ render "some_view"
51
+
52
+ component AuthorComponent, author: @post.author
53
+ end
54
+ end
55
+ end
56
+
57
+ let(:post) do
58
+ double(
59
+ title: "Test Post",
60
+ author: "Roger Nesbitt",
61
+ posted_at: Time.parse("2016-11-28 11:09:20"),
62
+ )
63
+ end
64
+
65
+ let(:view) { FakeView.new }
66
+
67
+ it "renders the component" do
68
+ result = TestComponent.render(view, post: post)
69
+ expect(result).to be nil
70
+
71
+ expect(view.calls).to eq [
72
+ [:content_tag, "div", {:class=>"post"}],
73
+ [:content_tag, "h2", "Test Post", nil],
74
+ [:concat, "content_tag [\"h2\", \"Test Post\", nil]"],
75
+ [:content_tag, "div", "28 November 2016 11:09", {:class=>"datetime"}],
76
+ [:concat, "content_tag [\"div\", \"28 November 2016 11:09\", {:class=>\"datetime\"}]"],
77
+ [:render, "some_view"],
78
+ [:concat, "render [\"some_view\"]"],
79
+ [:content_tag, "div", "Roger Nesbitt", nil],
80
+ [:concat, "content_tag [\"div\", \"Roger Nesbitt\", nil]"],
81
+ [:concat, "content_tag [\"div\", {:class=>\"post\"}]"],
82
+ ]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActionComponent::Constraints do
4
+ class ConstraintsTest
5
+ include ActionComponent::Constraints
6
+
7
+ required :apple, :banana, carrot: String
8
+ optional durian: Hash
9
+
10
+ def check(opts)
11
+ check_constraints!(opts)
12
+ end
13
+ end
14
+
15
+ subject { ConstraintsTest.new }
16
+
17
+ it "passes if all required attributes are supplied" do
18
+ subject.check(apple: 1, banana: 2, carrot: "hello", other: "ignored")
19
+ end
20
+
21
+ it "requires required attributes" do
22
+ expect { subject.check(apple: 1) }.to raise_error(ActionComponent::ConstraintError, "banana is required for component ConstraintsTest")
23
+
24
+ expect { subject.check(apple: 1, banana: 1) }.to raise_error(ActionComponent::ConstraintError, "carrot is required for component ConstraintsTest")
25
+ end
26
+
27
+ it "enforces type for required attributes" do
28
+ expect { subject.check(apple: 1, banana: 1, carrot: 1) }.to raise_error(ActionComponent::ConstraintError, "carrot must be a String")
29
+ end
30
+
31
+ it "enforces type for optional attributes" do
32
+ expect { subject.check(apple: 1, banana: 1, carrot: "hello", durian: 1) }.to raise_error(ActionComponent::ConstraintError, "durian must be a Hash")
33
+ end
34
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActionComponent::Elements do
4
+ class ElementsTest
5
+ include ActionComponent::Elements
6
+
7
+ define_tags :custom, :interesting
8
+
9
+ def initialize(view)
10
+ @_view = view
11
+ end
12
+ end
13
+
14
+ let(:view) { FakeView.new }
15
+
16
+ subject { ElementsTest.new(view) }
17
+
18
+ describe "::define_tags" do
19
+ it "creates methods for the defined tags" do
20
+ expect(subject.respond_to?(:custom, true)).to be true
21
+ expect(subject.respond_to?(:interesting, true)).to be true
22
+ expect(subject.respond_to?(:does_not_exist, true)).to be false
23
+ end
24
+ end
25
+
26
+ describe "#text" do
27
+ it "concats the supplied text" do
28
+ subject.send(:text, "some content")
29
+
30
+ expect(view.calls).to eq [[:concat, 'some content']]
31
+ end
32
+ end
33
+
34
+ describe "#doctype" do
35
+ it "concats a doctype tag" do
36
+ subject.send(:doctype)
37
+
38
+ expect(view.calls).to eq [[:concat, '<!doctype html>']]
39
+ end
40
+
41
+ it "concats a doctype tag with custom text" do
42
+ subject.send(:doctype, "<test>")
43
+
44
+ expect(view.calls).to eq [[:concat, '<!doctype &lt;test&gt;>']]
45
+ end
46
+ end
47
+
48
+ describe "an example of a define tag" do
49
+ it "calls element with its tag name as the first parameter" do
50
+ subject.send(:div, "div text", attribute: 'value')
51
+
52
+ expect(view.calls).to eq [
53
+ [:content_tag, "div", "div text", {:attribute=>"value"}],
54
+ [:concat, "content_tag [\"div\", \"div text\", {:attribute=>\"value\"}]"]
55
+ ]
56
+ end
57
+ end
58
+
59
+ describe "#element" do
60
+ context "when no arguments are specified" do
61
+ it "makes a tag" do
62
+ subject.send(:element, :name)
63
+
64
+ expect(view.calls).to eq [
65
+ [:tag, :name, nil],
66
+ [:concat, "tag [:name, nil]"],
67
+ ]
68
+ end
69
+ end
70
+
71
+ context "when only one non-hash argument is specified" do
72
+ it "makes a content_tag with that argument" do
73
+ subject.send(:element, :name, "text")
74
+
75
+ expect(view.calls).to eq [
76
+ [:content_tag, :name, 'text', nil],
77
+ [:concat, "content_tag [:name, \"text\", nil]"],
78
+ ]
79
+ end
80
+ end
81
+
82
+ context "when only one hash argument is specified" do
83
+ it "makes a tag using attributes from that argument" do
84
+ subject.send(:element, :name, blue: 'very')
85
+
86
+ expect(view.calls.first).to eq [:tag, :name, {blue: 'very'}]
87
+ end
88
+ end
89
+
90
+ context "when two arguments are specified" do
91
+ it "makes a content_tag using the text and attributes" do
92
+ subject.send(:element, :name, 'text', blue: 'very')
93
+
94
+ expect(view.calls.first).to eq [:content_tag, :name, 'text', {blue: 'very'}]
95
+ end
96
+ end
97
+
98
+ context "when one argument and a block is specified" do
99
+ it "makes a content_tag with the attributes and yields" do
100
+ called = false
101
+ subject.send(:element, :name, blue: 'very') { called = true }
102
+
103
+ expect(called).to be true
104
+ expect(view.calls.first).to eq [:content_tag, :name, {blue: 'very'}]
105
+ end
106
+ end
107
+
108
+ context "when text and a block are specified" do
109
+ it "raises" do
110
+ expect {
111
+ subject.send(:element, :name, 'hello') { 'yielded' }
112
+ }.to raise_error ActionComponent::RenderError
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,21 @@
1
+ example_id | status | run_time |
2
+ ------------------------------------------------- | ------ | --------------- |
3
+ ./spec/action_component/base_spec.rb[1:1:1] | passed | 0.01317 seconds |
4
+ ./spec/action_component/base_spec.rb[1:2:1] | passed | 0.00018 seconds |
5
+ ./spec/action_component/base_spec.rb[1:3:1] | passed | 0.00012 seconds |
6
+ ./spec/action_component/base_spec.rb[1:4:1] | passed | 0.00139 seconds |
7
+ ./spec/action_component/constraints_spec.rb[1:1] | passed | 0.00006 seconds |
8
+ ./spec/action_component/constraints_spec.rb[1:2] | passed | 0.00012 seconds |
9
+ ./spec/action_component/constraints_spec.rb[1:3] | passed | 0.00017 seconds |
10
+ ./spec/action_component/constraints_spec.rb[1:4] | passed | 0.00202 seconds |
11
+ ./spec/action_component/elements_spec.rb[1:1:1] | passed | 0.00017 seconds |
12
+ ./spec/action_component/elements_spec.rb[1:2:1] | passed | 0.00009 seconds |
13
+ ./spec/action_component/elements_spec.rb[1:3:1] | passed | 0.00015 seconds |
14
+ ./spec/action_component/elements_spec.rb[1:3:2] | passed | 0.00448 seconds |
15
+ ./spec/action_component/elements_spec.rb[1:4:1] | passed | 0.00014 seconds |
16
+ ./spec/action_component/elements_spec.rb[1:5:1:1] | passed | 0.00015 seconds |
17
+ ./spec/action_component/elements_spec.rb[1:5:2:1] | passed | 0.0001 seconds |
18
+ ./spec/action_component/elements_spec.rb[1:5:3:1] | passed | 0.00019 seconds |
19
+ ./spec/action_component/elements_spec.rb[1:5:4:1] | passed | 0.00014 seconds |
20
+ ./spec/action_component/elements_spec.rb[1:5:5:1] | passed | 0.00148 seconds |
21
+ ./spec/action_component/elements_spec.rb[1:5:6:1] | passed | 0.00024 seconds |
@@ -0,0 +1,20 @@
1
+ class FakeView
2
+ attr_reader :calls
3
+
4
+ def initialize
5
+ @calls = []
6
+ end
7
+
8
+ def datetime_formatter(time)
9
+ time.strftime("%d %B %Y %H:%M")
10
+ end
11
+
12
+ def method_missing(method, *args)
13
+ @calls << [method, *args]
14
+
15
+ yield if block_given?
16
+
17
+ "#{method} #{args.inspect}"
18
+ end
19
+ end
20
+
@@ -0,0 +1,102 @@
1
+ require_relative '../lib/action_component'
2
+ require_relative "fake_view"
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
7
+ # this file to always be loaded, without a need to explicitly require it in any
8
+ # files.
9
+ #
10
+ # Given that it is always loaded, you are encouraged to keep this file as
11
+ # light-weight as possible. Requiring heavyweight dependencies from this file
12
+ # will add to the boot time of your test suite on EVERY test run, even for an
13
+ # individual file that may not need all of that loaded. Instead, consider making
14
+ # a separate helper file that requires the additional dependencies and performs
15
+ # the additional setup, and require it from the spec files that actually need
16
+ # it.
17
+ #
18
+ # The `.rspec` file also contains a few flags that are not defaults but that
19
+ # users commonly want.
20
+ #
21
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
22
+ RSpec.configure do |config|
23
+ # rspec-expectations config goes here. You can use an alternate
24
+ # assertion/expectation library such as wrong or the stdlib/minitest
25
+ # assertions if you prefer.
26
+ config.expect_with :rspec do |expectations|
27
+ # This option will default to `true` in RSpec 4. It makes the `description`
28
+ # and `failure_message` of custom matchers include text for helper methods
29
+ # defined using `chain`, e.g.:
30
+ # be_bigger_than(2).and_smaller_than(4).description
31
+ # # => "be bigger than 2 and smaller than 4"
32
+ # ...rather than:
33
+ # # => "be bigger than 2"
34
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
35
+ end
36
+
37
+ # rspec-mocks config goes here. You can use an alternate test double
38
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
39
+ config.mock_with :rspec do |mocks|
40
+ # Prevents you from mocking or stubbing a method that does not exist on
41
+ # a real object. This is generally recommended, and will default to
42
+ # `true` in RSpec 4.
43
+ mocks.verify_partial_doubles = true
44
+ end
45
+
46
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
47
+ # have no way to turn it off -- the option exists only for backwards
48
+ # compatibility in RSpec 3). It causes shared context metadata to be
49
+ # inherited by the metadata hash of host groups and examples, rather than
50
+ # triggering implicit auto-inclusion in groups with matching metadata.
51
+ config.shared_context_metadata_behavior = :apply_to_host_groups
52
+
53
+ # This allows you to limit a spec run to individual examples or groups
54
+ # you care about by tagging them with `:focus` metadata. When nothing
55
+ # is tagged with `:focus`, all examples get run. RSpec also provides
56
+ # aliases for `it`, `describe`, and `context` that include `:focus`
57
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
58
+ config.filter_run_when_matching :focus
59
+
60
+ # Allows RSpec to persist some state between runs in order to support
61
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
62
+ # you configure your source control system to ignore this file.
63
+ config.example_status_persistence_file_path = "spec/examples.txt"
64
+
65
+ # Limits the available syntax to the non-monkey patched syntax that is
66
+ # recommended. For more details, see:
67
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
68
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
69
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
70
+ config.disable_monkey_patching!
71
+
72
+ # This setting enables warnings. It's recommended, but in some cases may
73
+ # be too noisy due to issues in dependencies.
74
+ config.warnings = true
75
+
76
+ # Many RSpec users commonly either run the entire suite or an individual
77
+ # file, and it's useful to allow more verbose output when running an
78
+ # individual spec file.
79
+ if config.files_to_run.one?
80
+ # Use the documentation formatter for detailed output,
81
+ # unless a formatter has already been configured
82
+ # (e.g. via a command-line flag).
83
+ config.default_formatter = 'doc'
84
+ end
85
+
86
+ # Print the 10 slowest examples and example groups at the
87
+ # end of the spec run, to help surface which specs are running
88
+ # particularly slow.
89
+ # config.profile_examples = 10
90
+
91
+ # Run specs in random order to surface order dependencies. If you find an
92
+ # order dependency and want to debug it, you can fix the order by providing
93
+ # the seed, which is printed after each run.
94
+ # --seed 1234
95
+ config.order = :random
96
+
97
+ # Seed global randomization in this process using the `--seed` CLI option.
98
+ # Setting this allows you to use `--seed` to deterministically reproduce
99
+ # test failures related to randomization by passing the same `--seed` value
100
+ # as the one that triggered the failure.
101
+ Kernel.srand config.seed
102
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-27 00:00:00.000000000 Z
11
+ date: 2016-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: railties
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '4'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -61,14 +75,25 @@ extensions: []
61
75
  extra_rdoc_files: []
62
76
  files:
63
77
  - ".gitignore"
78
+ - ".rspec"
79
+ - Gemfile
80
+ - Gemfile.lock
64
81
  - README.md
65
82
  - action_component.gemspec
66
83
  - lib/action_component.rb
67
84
  - lib/action_component/action_controller_rendering.rb
68
85
  - lib/action_component/action_view_rendering.rb
69
86
  - lib/action_component/base.rb
87
+ - lib/action_component/constraints.rb
88
+ - lib/action_component/elements.rb
70
89
  - lib/action_component/railtie.rb
71
90
  - lib/action_component/version.rb
91
+ - spec/action_component/base_spec.rb
92
+ - spec/action_component/constraints_spec.rb
93
+ - spec/action_component/elements_spec.rb
94
+ - spec/examples.txt
95
+ - spec/fake_view.rb
96
+ - spec/spec_helper.rb
72
97
  homepage: https://github.com/mogest/action_component
73
98
  licenses:
74
99
  - MIT
@@ -93,4 +118,10 @@ rubygems_version: 2.5.1
93
118
  signing_key:
94
119
  specification_version: 4
95
120
  summary: React-style components for Rails
96
- test_files: []
121
+ test_files:
122
+ - spec/action_component/base_spec.rb
123
+ - spec/action_component/constraints_spec.rb
124
+ - spec/action_component/elements_spec.rb
125
+ - spec/examples.txt
126
+ - spec/fake_view.rb
127
+ - spec/spec_helper.rb