action_widget 0.5.1 → 0.6.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0064d71b6d2394b297e64a6fa7dcbe74de2c8bb
4
- data.tar.gz: 84ced9363a9d26829c241ec189d18d318609be25
3
+ metadata.gz: 65f04e0efe22c4a80632c8bb2788b48f60c0d1d9
4
+ data.tar.gz: 2319ca299e05f2611cef8a1f420f886dcaebadfa
5
5
  SHA512:
6
- metadata.gz: 72f994bbf840c022f8c6c0038e26b78c9454a7e816806e9b6a7826e72de5ed187bddf9fa6597dfc0f66af6c619e57d6fbf025cf442bcb5b31382e7911fdb0025
7
- data.tar.gz: 58a3598ec1cfef5167831f3657a44db4c6c3f01080e6a6579b7f7f576ab93ec49041cf03a6a086fd23d558f4418127ad4c146fd6cefb5d71b2f7fba96c29cb83
6
+ metadata.gz: 90bda59277298cee6d43f1e98580fd812def0f5a6de6a1066ac762a470cf04d0ef2b4dac78798e264f5cd197dc51ea13f448ba7b1371fb44e9cde66024c19efb
7
+ data.tar.gz: d715ab381e066c58275390dda86e5f1156bfba030519c8292db06fcd0ecf017a61ca3624ea00f199e97b1e6996d1f908e0891be776d0e9a3988a2ca804dc985f
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  .rvmrc
19
+ .rspec
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 2.2.2
3
+ - 1.9.3
4
+
5
+ bundler_args: --without documentation
data/README.md CHANGED
@@ -1,6 +1,23 @@
1
1
  # ActionWidget
2
2
 
3
- TODO: Write a gem description
3
+ `ActionWidget` is a light-weight widget system for [Ruby on
4
+ Rails](http://rubyonrails.com) and [Middleman](http://middlemanapp.com). It is
5
+ essentially a minimal tool set for building desktop-like UI components. The
6
+ main idea behind `ActionWidget` is the separation of the concept of an UI
7
+ component and its representation. While the representation of component might
8
+ easily change over time, the concept of a component is unlikely to change
9
+ significantly. Think of a button for instance: Most developers will agree that
10
+ a button is conceptually something that has a caption and when clicked triggers
11
+ an action. When we think about the visual representation of a button, however,
12
+ things get more complicated. While most people will agree to a certain degree
13
+ on what can visually be considered a button and what is something else, people
14
+ tend to have different ideas about a button's exact representation. There are
15
+ buttons with icons, without icons, round ones, rectangular ones, and so on.
16
+ Despite their different appearances, the functionality and in this sense the
17
+ component's concept stays the same: when clicked an action is triggered.
18
+ ActionWidget provides developers with a tool set that helps them to strictly
19
+ decouple a component's concept from its representation to support future
20
+ change.
4
21
 
5
22
  ## Installation
6
23
 
@@ -18,7 +35,274 @@ Or install it yourself as:
18
35
 
19
36
  ## Usage
20
37
 
21
- TODO: Write usage instructions here
38
+ `ActionWidget` can be used to build arbitrarily complex view components. To
39
+ illustrate the basic usage of `ActionWidget`, however, we start with a simple
40
+ example, a widget for representing a button. We then continue with widgets that
41
+ except blocks. We will use a widget representing panels as an example. Finally,
42
+ we see discuss how to build widgets that utilize widgets themselves for
43
+ constructing navigation components.
44
+
45
+ ### Simple Widgets
46
+
47
+ The goal of this section is to build a widget that represents a button. The
48
+ button we are designing must have a `caption` and a `type`. The type can either
49
+ be `regular`, `accept`, or `cancel`. The button further must have a specified
50
+ `size`, which can be `small`, `medium`, or `large`. Finally, the button
51
+ requires a `target` that defines the resource it links to. `ActionWidget`
52
+ compentens utilize [SmartProperties](http://github.com/t6d/smart_properties) to
53
+ define attributes that can be configured to automatically enforce these
54
+ constraints and provide sensible defaults.
55
+
56
+ In the example below, we simple use an `<a>` tag to represent a button. The
57
+ attributes `size` and `type` are simply translated into CSS classes. The
58
+ `caption` will be used as the text encolsed by the `<a>` tag and the `target`
59
+ will be used as the value the the `<a>` tag's `href` attribute.
60
+
61
+ ```ruby
62
+ class ButtonWidget < ActionWidget::Base
63
+ property :caption,
64
+ converts: :to_s,
65
+ required: true
66
+
67
+ property :target,
68
+ converts: :to_s,
69
+ accepts: lambda { |uri| URI.parse(uri) rescue false },
70
+ required: true
71
+
72
+ property :type,
73
+ converts: :to_sym,
74
+ accepts: [:regular, :accept, :cancel],
75
+ default: :regular
76
+
77
+ property :size,
78
+ converts: :to_sym,
79
+ accepts: [:small, :medium, :large],
80
+ default: :medium
81
+
82
+ def render
83
+ content_tag(:a, caption, href: target, class: css_classes)
84
+ end
85
+
86
+ protected
87
+
88
+ def css_classes
89
+ css_classes = ['btn']
90
+ css_classes << "btn-#{size}" unless size == :regular
91
+ css_classes << "btn-#{type}" unless type == :medium
92
+ css_classes
93
+ end
94
+ end
95
+ ```
96
+
97
+ By convention, a widget's class name should end in "Widget". This way,
98
+ `ActionWidget` automatically generates `ActionView` helper methods for more
99
+ convenient instantiation and rendering of a widget.
100
+
101
+ In our example, the widget can be instantiated by simply calling the helper
102
+ method `button_widget` and providing it with all necessary attributes:
103
+
104
+ ```erb
105
+ <%= button_widget caption: 'Go to Admin Area', size: :small, target: '/admin' %>
106
+ ```
107
+
108
+ Instead of using the provided helper method, a widget can always be instantiated
109
+ manually:
110
+
111
+ ```erb
112
+ <%= ButtonWidget.new(self, caption: 'Go to Admin Area', size: :small, target: '/admin').render %>
113
+ ```
114
+
115
+ In both cases, the resulting HTML looks as follows:
116
+
117
+ ```html
118
+ <a class="btn btn-small" href="/admin">Go to Admin Area</a>
119
+ ```
120
+
121
+ ### Widgets that Accept Blocks
122
+
123
+ The panel widget we are building requires a `title` and a block that defines the
124
+ widgets content.
125
+
126
+ ```ruby
127
+ require 'action_widget'
128
+
129
+ class PanelWidget < ActionWidget::Base
130
+ property :title, required: true, converts: :to_s
131
+
132
+ def render(&block)
133
+ content_tag(:div, class: 'panel') do
134
+ content_tag(:h2, title, class: 'title') +
135
+ content_tag(:div, class: 'content', &block)
136
+ end
137
+ end
138
+ end
139
+ ```
140
+
141
+ Again, the automatically generated helper method, `#panel_widget` in this case,
142
+ can be used to instantiate and render the widget:
143
+
144
+ ```erb
145
+ <%= panel_widget title: "Important Notice" do %>
146
+ The system will be down for maintanence today.
147
+ <% end %>
148
+ ```
149
+
150
+ Executing the code above results in the follwing HTML:
151
+
152
+ ```html
153
+ <div class="panel">
154
+ <h2 class="title">Important Notice</h2>
155
+ <div class="content">
156
+ The system will be down for maintanence today.
157
+ </div>
158
+ </div>
159
+ ```
160
+
161
+ Since widgets are simple Ruby classes, they naturally support inheritance.
162
+ Let's assume we require a special panel widget for sidebars that renders a
163
+ different header. There are two options:
164
+
165
+ 1. we can provide the tag that is chosen for the header as a property, or
166
+ 2. we restructure the `PanelWidget` class and then subclass it.
167
+
168
+ Let's take the second approach and extract the header rendering and the content
169
+ rendering into their own methods so we can overwrite either one of them in a
170
+ potential subclass.
171
+
172
+ ```ruby
173
+ class PanelWidget < ActionWidget::Base
174
+ property :title, required: true, converts: :to_s
175
+
176
+ def render(&block)
177
+ header + content(&block)
178
+ end
179
+
180
+ protected
181
+
182
+ def header
183
+ content_tag(:h2, title)
184
+ end
185
+
186
+ def content(&block)
187
+ content_tag(:div, &block)
188
+ end
189
+ end
190
+ ```
191
+
192
+ After this refactoring, we are able to subclass `PanelWidget` and customize the
193
+ `header` method:
194
+
195
+ ```ruby
196
+ class SidebarPanelWidget < PanelWidget
197
+ protected
198
+
199
+ def header
200
+ content_tag(:h3, title)
201
+ end
202
+ end
203
+ ```
204
+
205
+ ### Nested Widgets
206
+
207
+ Let's assume we want to implement a widget that simplifies the rendering of
208
+ navigational menus. The widget only exposes one property, `orientation`, which
209
+ can either be `horizontal` or `vertical`.
210
+
211
+ ```ruby
212
+ class MenuWidget < ActionWidget::Base
213
+ property :orientation,
214
+ accepts: [:horizontal, :vertical],
215
+ converts: :to_sym,
216
+ default: :horizontal,
217
+ required: true
218
+
219
+ def render(&block)
220
+ content_tag(:nav, class: orientation) do
221
+ content_tag(:ul) do
222
+ capture(self, &block)
223
+ end
224
+ end
225
+ end
226
+
227
+ def item(caption, target)
228
+ content_tag(:li) do
229
+ content_tag(:a, caption, href: target)
230
+ end
231
+ end
232
+
233
+ def submenu(caption, &block)
234
+ content_tag(:li) do
235
+ content_tag(:span, caption) +
236
+ self.class.new(view, orientation: orientation).render(&block)
237
+ end
238
+ end
239
+ end
240
+ ```
241
+
242
+ The following example demonstrates how to use this widget:
243
+
244
+ ```erb
245
+ <%= menu_widget do |m| %>
246
+ <%= m.item "Dashboard", "/" %>
247
+ <%= m.submenu "Admin" do |m| %>
248
+ <%= m.item "Manage Users", "/admin/users" %>
249
+ <%= m.item "Manage Groups", "/admin/groups" %>
250
+ <% end %>
251
+ <% end %>
252
+ ```
253
+
254
+ Executing the code above, will result in the following HTML being generated:
255
+
256
+ ```html
257
+ <nav class="horizontal">
258
+ <ul>
259
+ <li> <a href="/">Dashboard</a> </li>
260
+ <li>
261
+ <span>Admin</span>
262
+ <nav class="horizontal">
263
+ <ul>
264
+ <li><a href="/admin/users">Manage Users</a></li>
265
+ <li><a href="/admin/groups">Manage Groups</a></li>
266
+ </ul>
267
+ </nav>
268
+ </li>
269
+ </ul>
270
+ </nav>
271
+ ```
272
+
273
+ ### Option Capturing and Positional Argument Forwarding
274
+
275
+ `ActionWidget` instances capture all initializer keyword
276
+ arguments that do not correspond to a property in a general `options` hash.
277
+ All positional arguments supplied to an autogenerated helper are
278
+ forwarded to the `render` method.
279
+
280
+ ```ruby
281
+ class ParagraphWidget < ActionWidget::Base
282
+ def render(content, &block)
283
+ content = capture(&block) if block
284
+ content_tag(:p, content, class: options[:class])
285
+ end
286
+ end
287
+ ```
288
+
289
+ This widget can be used in the following two ways:
290
+
291
+ ```erb
292
+ <%= paragraph_widget("Some content", class: 'important') %>
293
+
294
+ <%= paragraph_widget(class: 'important') do %>
295
+ Some content
296
+ <% end %>
297
+ ```
298
+
299
+ In both cases, the resulting HTML reads as follows:
300
+
301
+ ```html
302
+ <p class="important">
303
+ Some content
304
+ </p>
305
+ ```
22
306
 
23
307
  ## Contributing
24
308
 
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
@@ -10,7 +10,11 @@ Gem::Specification.new do |gem|
10
10
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11
11
  gem.name = "action_widget"
12
12
  gem.require_paths = ["lib"]
13
- gem.version = "0.5.1"
13
+ gem.version = "0.6.0.pre"
14
14
 
15
- gem.add_dependency 'smart_properties', '~> 1.1'
15
+ gem.add_dependency 'smart_properties', '~> 1.10'
16
+
17
+ gem.add_development_dependency 'rake', '~> 10.0'
18
+ gem.add_development_dependency 'rspec', '~> 3.3'
19
+ gem.add_development_dependency 'actionview', '~> 4.0'
16
20
  end
@@ -1,31 +1,21 @@
1
- require 'smart_properties'
2
-
3
1
  module ActionWidget
4
- class Base
2
+ class Base < SimpleDelegator
3
+ alias view __getobj__
5
4
  include SmartProperties
6
5
 
7
- def initialize(view, *args)
8
- @view = view
9
- super(*args)
6
+ attr_reader :options
7
+
8
+ def initialize(view, attributes = {})
9
+ properties = self.class.properties
10
+ attributes, options = attributes.partition { |name, value| properties.key?(name) }
11
+
12
+ @options = Hash[options]
13
+ super(view, Hash[attributes])
10
14
  end
11
15
 
12
16
  def render
13
17
  raise NotImplementedError, "#{self.class} must implement #render"
14
18
  end
15
-
16
- protected
17
-
18
- attr_reader :view
19
-
20
- undef :capture if method_defined?(:capture)
21
-
22
- def method_missing(method, *args, &block)
23
- view.send(method, *args, &block)
24
- rescue NoMethodError
25
- # Double check - the NoMethodError might have occurred somewhere else.
26
- view.respond_to?(method) ? raise : super
27
- end
28
-
29
19
  end
30
20
  end
31
21
 
@@ -2,18 +2,19 @@ module ActionWidget
2
2
  module ViewHelper
3
3
 
4
4
  def method_missing(name, *args, &block)
5
- return super unless name =~ /_widget$/
5
+ return super unless ActionWidget.helper?(name)
6
6
 
7
7
  klass = begin
8
- "#{name.to_s.camelcase}".constantize
8
+ ActionWidget.class_for(name)
9
9
  rescue NameError, LoadError
10
10
  return super
11
11
  end
12
12
 
13
13
  ActionWidget::ViewHelper.module_eval <<-RUBY
14
- def #{name}(*args, &block) # def example_widget(*args, &block)
15
- #{klass}.new(self, *args).render(&block) # ExampleWidget.new(self, *args).render(&block)
16
- end # end
14
+ def #{name}(*args, &block) # def example_widget(*args, &block)
15
+ attrs = args.last.kind_of?(Hash) ? args.pop : {}
16
+ #{klass}.new(self, attrs).render(*args, &block) # ExampleWidget.new(self, attrs).render(*args, &block)
17
+ end # end
17
18
  RUBY
18
19
 
19
20
  send(name, *args, &block)
data/lib/action_widget.rb CHANGED
@@ -1,3 +1,45 @@
1
+ require 'smart_properties'
2
+
3
+ module ActionWidget
4
+ class Configuration
5
+ include SmartProperties
6
+ property :prefix
7
+ property :suffix
8
+
9
+ attr_reader :pattern
10
+
11
+ def initialize(*)
12
+ super
13
+
14
+ @pattern = Regexp.new([
15
+ (prefix.underscore if prefix.presence),
16
+ "(.*)",
17
+ (suffix.underscore if suffix.presence)
18
+ ].compact.join("_"))
19
+ end
20
+ end
21
+
22
+ class << self
23
+ def configuration
24
+ @configuration ||= Configuration.new(suffix: "Widget")
25
+ end
26
+
27
+ def configure(&block)
28
+ @configuration = Configuration.new(&block)
29
+ end
30
+
31
+ def helper?(name)
32
+ !!configuration.pattern.match(name)
33
+ end
34
+
35
+ def class_for(helper_name)
36
+ basename = configuration.pattern.match(helper_name)[1]
37
+ classname = [configuration.prefix, basename.camelcase, configuration.suffix].join("")
38
+ classname.constantize
39
+ end
40
+ end
41
+ end
42
+
1
43
  require 'action_widget/base'
2
44
  require 'action_widget/view_helper'
3
- require 'action_widget/extensions'
45
+ require 'action_widget/extensions'
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ class DummyWidget < ActionWidget::Base
4
+ property :type
5
+
6
+ def render(content = nil)
7
+ classes = [options[:class], type].compact
8
+ if classes.empty?
9
+ content_tag(:p, content)
10
+ else
11
+ content_tag(:p, content, class: classes)
12
+ end
13
+ end
14
+ end
15
+
16
+ class ViewContext < ActionView::Base
17
+ include ActionWidget::ViewHelper
18
+ end
19
+
20
+ RSpec.describe DummyWidget do
21
+ let(:view) { ViewContext.new }
22
+
23
+ it "should delegate unknown method calls to the view context" do
24
+ expect(described_class.new(view).render).to eq("<p></p>")
25
+ end
26
+
27
+ context "option capturing and positional argument forwarding" do
28
+ let(:expected_html) { '<p class="wide teaser">Hello World</p>' }
29
+
30
+ it "should be possible to reference a property using a symbol" do
31
+ attributes = {type: 'teaser', class: 'wide'}
32
+ expect(view.dummy_widget("Hello World", attributes)).to eq(expected_html)
33
+ end
34
+
35
+ it "should be possible to reference a property using a string" do
36
+ attributes = {"type" => 'teaser', class: 'wide'}
37
+ expect(view.dummy_widget("Hello World", attributes)).to eq(expected_html)
38
+ end
39
+
40
+ specify "keyword arguments that do not correspond to a property should be captured as options" do
41
+ instance = described_class.new(view, class: 'wide')
42
+ expect(instance.options).to eq({class: 'wide'})
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,82 @@
1
+ require 'bundler/setup'
2
+ require 'rspec'
3
+ require 'action_view'
4
+
5
+ require 'action_widget'
6
+
7
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
8
+ RSpec.configure do |config|
9
+ # rspec-expectations config goes here. You can use an alternate
10
+ # assertion/expectation library such as wrong or the stdlib/minitest
11
+ # assertions if you prefer.
12
+ config.expect_with :rspec do |expectations|
13
+ # This option will default to `true` in RSpec 4. It makes the `description`
14
+ # and `failure_message` of custom matchers include text for helper methods
15
+ # defined using `chain`, e.g.:
16
+ # be_bigger_than(2).and_smaller_than(4).description
17
+ # # => "be bigger than 2 and smaller than 4"
18
+ # ...rather than:
19
+ # # => "be bigger than 2"
20
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
21
+ end
22
+
23
+ # rspec-mocks config goes here. You can use an alternate test double
24
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
25
+ config.mock_with :rspec do |mocks|
26
+ # Prevents you from mocking or stubbing a method that does not exist on
27
+ # a real object. This is generally recommended, and will default to
28
+ # `true` in RSpec 4.
29
+ mocks.verify_partial_doubles = true
30
+ end
31
+
32
+ # These two settings work together to allow you to limit a spec run
33
+ # to individual examples or groups you care about by tagging them with
34
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
35
+ # get run.
36
+ config.filter_run :focus
37
+ config.run_all_when_everything_filtered = true
38
+
39
+ # Allows RSpec to persist some state between runs in order to support
40
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
41
+ # you configure your source control system to ignore this file.
42
+ #
43
+ # config.example_status_persistence_file_path = "spec/examples.txt"
44
+
45
+ # Limits the available syntax to the non-monkey patched syntax that is
46
+ # recommended. For more details, see:
47
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
48
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
49
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
50
+ config.disable_monkey_patching!
51
+
52
+ # This setting enables warnings. It's recommended, but in some cases may
53
+ # be too noisy due to issues in dependencies.
54
+ config.warnings = true
55
+
56
+ # Many RSpec users commonly either run the entire suite or an individual
57
+ # file, and it's useful to allow more verbose output when running an
58
+ # individual spec file.
59
+ if config.files_to_run.one?
60
+ # Use the documentation formatter for detailed output,
61
+ # unless a formatter has already been configured
62
+ # (e.g. via a command-line flag).
63
+ config.default_formatter = 'doc'
64
+ end
65
+
66
+ # Print the 10 slowest examples and example groups at the
67
+ # end of the spec run, to help surface which specs are running
68
+ # particularly slow.
69
+ config.profile_examples = 10
70
+
71
+ # Run specs in random order to surface order dependencies. If you find an
72
+ # order dependency and want to debug it, you can fix the order by providing
73
+ # the seed, which is printed after each run.
74
+ # --seed 1234
75
+ config.order = :random
76
+
77
+ # Seed global randomization in this process using the `--seed` CLI option.
78
+ # Setting this allows you to use `--seed` to deterministically reproduce
79
+ # test failures related to randomization by passing the same `--seed` value
80
+ # as the one that triggered the failure.
81
+ Kernel.srand config.seed
82
+ end
metadata CHANGED
@@ -1,29 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_widget
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Tennhard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-22 00:00:00.000000000 Z
11
+ date: 2015-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: smart_properties
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.1'
19
+ version: '1.10'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.1'
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: actionview
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
27
69
  description:
28
70
  email:
29
71
  - me@t6d.de
@@ -31,7 +73,8 @@ executables: []
31
73
  extensions: []
32
74
  extra_rdoc_files: []
33
75
  files:
34
- - .gitignore
76
+ - ".gitignore"
77
+ - ".travis.yml"
35
78
  - Gemfile
36
79
  - LICENSE
37
80
  - README.md
@@ -45,6 +88,8 @@ files:
45
88
  - lib/action_widget/extensions/rails/generators.rb
46
89
  - lib/action_widget/extensions/rails/railtie.rb
47
90
  - lib/action_widget/view_helper.rb
91
+ - spec/action_widget_spec.rb
92
+ - spec/spec_helper.rb
48
93
  - support/templates/widget.rb.erb
49
94
  - support/templates/widget_spec.rb.erb
50
95
  homepage: http://github.com/t6d/action_widget
@@ -56,19 +101,21 @@ require_paths:
56
101
  - lib
57
102
  required_ruby_version: !ruby/object:Gem::Requirement
58
103
  requirements:
59
- - - '>='
104
+ - - ">="
60
105
  - !ruby/object:Gem::Version
61
106
  version: '0'
62
107
  required_rubygems_version: !ruby/object:Gem::Requirement
63
108
  requirements:
64
- - - '>='
109
+ - - ">"
65
110
  - !ruby/object:Gem::Version
66
- version: '0'
111
+ version: 1.3.1
67
112
  requirements: []
68
113
  rubyforge_project:
69
- rubygems_version: 2.0.6
114
+ rubygems_version: 2.4.5
70
115
  signing_key:
71
116
  specification_version: 4
72
117
  summary: Reusable view components for your Ruby web application
73
- test_files: []
118
+ test_files:
119
+ - spec/action_widget_spec.rb
120
+ - spec/spec_helper.rb
74
121
  has_rdoc: