diff options
| author | Zog | 2018-01-17 15:49:39 +0100 |
|---|---|---|
| committer | Zog | 2018-01-25 17:18:00 +0100 |
| commit | ef62577ec90a0eb06c831052b6ab8aea8ade405f (patch) | |
| tree | c24c4deb965f3bb66835749aec1948eb06191d67 | |
| parent | 69d1f47e21fea3c151eabafcdd9051d9d10e92a3 (diff) | |
| download | chouette-core-ef62577ec90a0eb06c831052b6ab8aea8ade405f.tar.bz2 | |
Refs #5586; Add more specs on AF83::Decorator::Link
| -rw-r--r-- | lib/af83/decorator.rb | 146 | ||||
| -rw-r--r-- | lib/af83/decorator/link.rb | 153 | ||||
| -rw-r--r-- | spec/lib/af83/decorator/decorator_link_spec.rb | 75 |
3 files changed, 228 insertions, 146 deletions
diff --git a/lib/af83/decorator.rb b/lib/af83/decorator.rb index ba9a46cb0..53e09fed3 100644 --- a/lib/af83/decorator.rb +++ b/lib/af83/decorator.rb @@ -107,152 +107,6 @@ class AF83::Decorator < ModelDecorator end end - class Link - REQUIRED_ATTRIBUTES = %i(href content) - - attr_reader :context - attr_reader :action - - def initialize options={} - @options = options - end - - def bind_to_context context, action - @context = context - @action = action - self - end - - def method *args - link_method *args - end - - def class *args - link_class args - end - - def method_missing name, *args, &block - if block_given? - @options[name] = block - elsif args.size == 0 - out = @options[name] - out = context.instance_exec(self, &out) if out.is_a?(Proc) - out - else - @options[name] = args.first - end - end - - def options - @options.symbolize_keys - end - - def complete? - @missing_attributes = REQUIRED_ATTRIBUTES.select{|a| !@options[a].present?} - @missing_attributes.empty? - end - - def enabled_actions - @options[:_actions].map(&:to_s) || [] - end - - def for_action? action=nil - action ||= @action - enabled_actions.empty? || enabled_actions.include?(action.to_s) - end - - def actions_for_group group - val = @options[:_groups][group] - val.is_a?(Array) ? val.map(&:to_s) : val - end - - def in_group_for_action? group - vals = actions_for_group(group) - if vals.is_a?(Array) - return vals.include?(@action.to_s) - elsif vals.is_a?(String) || vals.is_a?(Symbol) - vals.to_s == @action.to_s - else - !!vals - end - end - - def primary? - in_group_for_action? :primary - end - - def secondary? - in_group_for_action? :secondary - end - - def enabled? - enabled = false - if @options[:_if].nil? - enabled = true - elsif @options[:_if].is_a?(Proc) - enabled = context.instance_exec(&@options[:_if]) - else - enabled = !!@options[:_if] - end - - enabled = enabled && check_policy(@options[:_policy]) if @options[:_policy].present? - enabled = enabled && check_feature(@options[:_feature]) if @options[:_feature].present? - - enabled - end - - def check_policy(policy) - @context.check_policy policy - end - - def check_feature(feature) - @context.check_feature feature - end - - def errors - "Missing attributes: #{@missing_attributes.to_sentence}" - end - - def extra_class val=nil - if val.present? - @options[:link_class] ||= [] - @options[:link_class] << val - @options[:link_class].flatten! - else - (options[:link_class] || []).join(' ') - end - end - - def html_options - out = {} - options.each do |k, v| - out[k] = self.send(k) unless k == :content || k == :href || k.to_s =~ /^_/ - end - out[:class] = extra_class - out.delete(:link_class) - out[:class] += " disabled" if disabled - out[:disabled] = !!disabled - out - end - - def to_html - if block_given? - link = Link.new(@options) - yield link - return link.bind_to_context(context, @action).to_html - end - if type&.to_sym == :button - HTMLElement.new( - :button, - content, - html_options - ).to_html - else - context.h.link_to content, href, html_options - end - end - end - class IncompleteLinkDefinition < RuntimeError end diff --git a/lib/af83/decorator/link.rb b/lib/af83/decorator/link.rb new file mode 100644 index 000000000..e7ab90d55 --- /dev/null +++ b/lib/af83/decorator/link.rb @@ -0,0 +1,153 @@ +class AF83::Decorator::Link + REQUIRED_ATTRIBUTES = %i(href content) + + attr_reader :context + attr_reader :action + + def initialize options={} + @options = {} + options.each do |k, v| + send "#{k}", v + end + end + + def bind_to_context context, action + @context = context + @action = action + self + end + + def method *args + link_method *args + end + + def class *args + link_class args + end + + def method_missing name, *args, &block + if block_given? + @options[name] = block + elsif args.size == 0 + out = @options[name] + out = context.instance_exec(self, &out) if out.is_a?(Proc) + out + else + # we can use l.foo("bar") or l.foo = "bar" + if name.to_s =~ /\=$/ + _name = name.to_s.gsub(/=$/, '') + return send(_name, *args, &block) + end + @options[name] = args.first + end + end + + def options + @options.symbolize_keys + end + + def complete? + @missing_attributes = REQUIRED_ATTRIBUTES.select{|a| !@options[a].present?} + @missing_attributes.empty? + end + + def enabled_actions + @options[:_actions].map(&:to_s) || [] + end + + def for_action? action=nil + action ||= @action + enabled_actions.empty? || enabled_actions.include?(action.to_s) + end + + def actions_for_group group + val = @options[:_groups][group] + val.is_a?(Array) ? val.map(&:to_s) : val + end + + def in_group_for_action? group + vals = actions_for_group(group) + if vals.is_a?(Array) + return vals.include?(@action.to_s) + elsif vals.is_a?(String) || vals.is_a?(Symbol) + vals.to_s == @action.to_s + else + !!vals + end + end + + def primary? + in_group_for_action? :primary + end + + def secondary? + in_group_for_action? :secondary + end + + def enabled? + enabled = false + if @options[:_if].nil? + enabled = true + elsif @options[:_if].is_a?(Proc) + enabled = context.instance_exec(&@options[:_if]) + else + enabled = !!@options[:_if] + end + + enabled = enabled && check_policy(@options[:_policy]) if @options[:_policy].present? + enabled = enabled && check_feature(@options[:_feature]) if @options[:_feature].present? + + enabled + end + + def check_policy(policy) + @context.check_policy policy + end + + def check_feature(feature) + @context.check_feature feature + end + + def errors + "Missing attributes: #{@missing_attributes.to_sentence}" + end + + def extra_class val=nil + if val.present? + @options[:link_class] ||= [] + @options[:link_class] << val + @options[:link_class].flatten! + else + (options[:link_class] || []).join(' ') + end + end + + def html_options + out = {} + options.each do |k, v| + out[k] = self.send(k) unless k == :content || k == :href || k.to_s =~ /^_/ + end + out[:class] = extra_class + out.delete(:link_class) + out[:class] += " disabled" if disabled + out[:disabled] = !!disabled + out + end + + def to_html + if block_given? + link = Link.new(@options) + yield link + return link.bind_to_context(context, @action).to_html + end + if type&.to_sym == :button + HTMLElement.new( + :button, + content, + html_options + ).to_html + else + context.h.link_to content, href, html_options + end + end +end diff --git a/spec/lib/af83/decorator/decorator_link_spec.rb b/spec/lib/af83/decorator/decorator_link_spec.rb new file mode 100644 index 000000000..356dcc527 --- /dev/null +++ b/spec/lib/af83/decorator/decorator_link_spec.rb @@ -0,0 +1,75 @@ +RSpec.describe AF83::Decorator::Link, type: :decorator do + describe "#complete?" do + context "on a imcomplete link" do + it "should be false" do + expect(AF83::Decorator::Link.new.complete?).to be_falsy + expect(AF83::Decorator::Link.new(content: "foo").complete?).to be_falsy + expect(AF83::Decorator::Link.new(href: "foo").complete?).to be_falsy + end + end + + context "on a complete link" do + it "should be true" do + expect(AF83::Decorator::Link.new(href: "foo", content: "foo").complete?).to be_truthy + end + end + end + + describe "#class" do + let(:link){ + AF83::Decorator::Link.new(href: "foo", content: "foo", class: "initial_class") + } + + it "should override exisiting class" do + expect(link.html_options[:class]).to eq "initial_class" + link.class "new_class" + expect(link.html_options[:class]).to eq "new_class" + link.class = "another_class" + expect(link.html_options[:class]).to eq "another_class" + end + end + + describe "#extra_class" do + let(:link){ + AF83::Decorator::Link.new(href: "foo", content: "foo", class: "initial_class") + } + + it "should add to exisiting class" do + expect(link.html_options[:class]).to eq "initial_class" + link.extra_class "new_class" + expect(link.html_options[:class]).to eq "initial_class new_class" + link.extra_class = "another_class" + expect(link.html_options[:class]).to eq "initial_class new_class another_class" + end + end + + describe "#type" do + + let(:link){ + AF83::Decorator::Link.new(href: "foo", content: "foo") + } + + let(:context){ + Class.new do + def h + Class.new do + def link_to *args + HTMLElement.new(:a, 'foo', {}).to_html + end + end.new + end + end.new + } + + it "should allow for buttons" do + link.type = :button + expect(link.to_html).to match /\<button.*\<\/button\>/ + end + + it "should fallback to <a>" do + link.type = :spaghetti + link.bind_to_context context, :show + expect(link.to_html).to match /\<a.*\<\/a\>/ + end + end +end |
