sir_trevor_rails 0.5.0b1 → 0.5.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -0
  3. data/app/views/sir_trevor/blocks/_heading_block.html.erb +3 -1
  4. data/app/views/sir_trevor/blocks/_list_block.html.erb +9 -1
  5. data/app/views/sir_trevor/blocks/_quote_block.html.erb +7 -1
  6. data/app/views/sir_trevor/blocks/_text_block.html.erb +1 -1
  7. data/app/views/sir_trevor/blocks/_tweet_block.html.erb +3 -3
  8. data/lib/generators/sir_trevor_rails/block/block_generator.rb +16 -11
  9. data/lib/generators/sir_trevor_rails/block/templates/_block.html.erb +3 -3
  10. data/lib/generators/sir_trevor_rails/block/templates/{_block.js → _block.js.erb} +4 -6
  11. data/lib/generators/sir_trevor_rails/block/templates/_block.rb.erb +2 -0
  12. data/lib/sir_trevor_rails/block.rb +15 -5
  13. data/lib/sir_trevor_rails/block_array.rb +17 -5
  14. data/lib/sir_trevor_rails/blocks/tweet_block.rb +6 -4
  15. data/lib/sir_trevor_rails/helpers/view_helper.rb +21 -2
  16. data/lib/sir_trevor_rails/version.rb +1 -1
  17. data/lib/sir_trevor_rails/view_resolver.rb +3 -3
  18. data/sir_trevor_rails.gemspec +4 -2
  19. data/spec/fixtures/blocks/custom.json +7 -0
  20. data/spec/fixtures/blocks/heading_html.json +7 -0
  21. data/spec/fixtures/blocks/heading_markdown.json +6 -0
  22. data/spec/fixtures/blocks/image.json +26 -0
  23. data/spec/fixtures/blocks/list_html.json +10 -0
  24. data/spec/fixtures/blocks/list_markdown.json +6 -0
  25. data/spec/fixtures/blocks/quote_html.json +8 -0
  26. data/spec/fixtures/blocks/quote_markdown.json +7 -0
  27. data/spec/fixtures/blocks/text_html.json +7 -0
  28. data/spec/fixtures/blocks/text_markdown.json +6 -0
  29. data/spec/fixtures/blocks/tweet.json +21 -0
  30. data/spec/integration/editing_spec.rb +19 -0
  31. data/spec/integration/rendering_spec.rb +121 -0
  32. data/spec/internal/app/controllers/posts_controller.rb +33 -0
  33. data/spec/internal/app/models/post.rb +2 -0
  34. data/spec/internal/app/views/posts/_form.html.erb +3 -0
  35. data/spec/internal/app/views/posts/edit.html.erb +3 -0
  36. data/spec/internal/app/views/posts/new.html.erb +3 -0
  37. data/spec/internal/app/views/posts/show.html.erb +1 -0
  38. data/spec/internal/config/routes.rb +1 -1
  39. data/spec/spec_helper.rb +42 -1
  40. data/spec/unit/block_array_spec.rb +21 -11
  41. data/spec/unit/block_spec.rb +10 -4
  42. data/spec/unit/custom_block_spec.rb +10 -8
  43. data/spec/unit/has_sir_trevor_content_spec.rb +2 -8
  44. data/spec/unit/helpers_spec.rb +44 -0
  45. metadata +96 -10
  46. data/lib/generators/sir_trevor_rails/block/templates/_block.rb +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0440542cac7ceda76800ef5d839ce166aea6a96
4
- data.tar.gz: 63bfbecf7f48260f978fd284bf773ec1cc8287c2
3
+ metadata.gz: 63883a02cdf49d08e2ecfc4b3ecd307396d4b9c8
4
+ data.tar.gz: 81b858f079c3632f141414bd4ed19b197edd1b05
5
5
  SHA512:
6
- metadata.gz: 41c835b01d6f5fd0bf4540ba2a3c65d3fcf70c43de7586ab3048fae21025bd05045c70c4afca5a9671dbbfe3a774e8e9f7a97dd9c3b97ff1840d7bf281135a3f
7
- data.tar.gz: 7621bdbeae052096553e9af079169a8f600aef8e8733acfdf02e0b3f91618455c8a44b3bcec27a0eb382fbb55fd52b1cfc0d32c9cd6e3f4d3cdf3c19821b9013
6
+ metadata.gz: d80735fb35626d3be73f46a844007c8b6541118b65f5d5db1b48401475dad94e9840b9564d236493457fb463e0eed2c9e35bb00d4043cd681b33021e9170cec2
7
+ data.tar.gz: 9e9d4e118c9c541d7afa0f2ce96152de64b1e136fb83561f3cc0f31c460e749515b96237b399c2534dfa04bdbd10dc1a46c5ffd79c613d570142f9f4827908ca
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - 2.2.2
7
+
8
+ script: 'bundle exec rake test'
@@ -1 +1,3 @@
1
- <h2><%= heading_block.text %></h2>
1
+ <h2 class="st__content-block st__content-block--heading">
2
+ <%= without_p_wrap(sir_trevor_format(heading_block.text, format: heading_block.format)) %>
3
+ </h2>
@@ -1,3 +1,11 @@
1
1
  <div class="st__content-block st__content-block--list">
2
- <%= sir_trevor_markdown list_block.text %>
2
+ <% if list_block.format == :html %>
3
+ <ul>
4
+ <% list_block.listItems.each do |item| %>
5
+ <li><%= sir_trevor_format item[:content], format: list_block.format %></li>
6
+ <% end %>
7
+ </ul>
8
+ <% else %>
9
+ <%= sir_trevor_markdown list_block.text %>
10
+ <% end %>
3
11
  </div>
@@ -1,7 +1,13 @@
1
1
  <div class="st__content-block st__content-block--quote">
2
2
  <div class="quote">
3
3
  <div class="quote__content">
4
- <%= sir_trevor_markdown quote_block.text %>
4
+ <% if quote_block.format == :html %>
5
+ <blockquote>
6
+ <%= sir_trevor_format quote_block.text, format: quote_block.format %>
7
+ </blockquote>
8
+ <% else %>
9
+ <%= sir_trevor_markdown quote_block.text %>
10
+ <% end %>
5
11
  </div>
6
12
 
7
13
  <% if quote_block.cite.present? %>
@@ -1,3 +1,3 @@
1
1
  <div class="st__content-block st__content-block--text">
2
- <%= sir_trevor_markdown text_block.text %>
2
+ <%= sir_trevor_format text_block.text, format: text_block.format%>
3
3
  </div>
@@ -1,9 +1,9 @@
1
1
  <div class="st__content-block st__content-block--tweet">
2
- <%= link_to image_tag(tweet_block.profile_image_url, class: 'img'), tweet_block.screen_name %>
2
+ <%= link_to image_tag(tweet_block.profile_image_url, class: 'img'), tweet_block.profile_url %>
3
3
  <p>
4
4
  <%= tweet_block.render_tweet_body %>
5
5
  </p>
6
- <cite>From <%= link_to tweet_block.at_name, tweet_block.screen_name %> on Twitter:</cite>
7
- <time datetime="<%= tweet_block.created_at %>">(<%= link_to Time.parse(tweet_block.created_at), tweet_block.status_url %>)</time>
6
+ <cite>From <%= link_to tweet_block.at_name, tweet_block.profile_url %> on Twitter:</cite>
7
+ <time datetime="<%= tweet_block.created_at %>">(<%= link_to Time.zone.parse(tweet_block.created_at), tweet_block.status_url %>)</time>
8
8
  </div>
9
9
 
@@ -11,23 +11,28 @@ module SirTrevorRails
11
11
  def create_block
12
12
 
13
13
  # Copy the JS
14
- copy_file "_block.js", "app/assets/javascripts/sir_trevor/blocks/#{name}.js"
15
-
16
- gsub_file "app/assets/javascripts/sir_trevor/blocks/#{name}.js", /SirTrevor\.Blocks\.Example/, "SirTrevor.Blocks.#{name.capitalize}"
17
- gsub_file "app/assets/javascripts/sir_trevor/blocks/#{name}.js", /return "Example"/, "return: '#{name.capitalize}'"
18
- gsub_file "app/assets/javascripts/sir_trevor/blocks/#{name}.js", /type: 'example'/, "type: '#{name.downcase}'"
14
+ template "_block.js.erb", "app/assets/javascripts/sir_trevor/blocks/#{file_name}.js"
19
15
 
20
16
  # Copy the HTML
21
- copy_file "_block.html.erb", "app/views/sir_trevor/blocks/_#{name}_block.html.erb"
22
- gsub_file "app/views/sir_trevor/blocks/_#{name}_block.html.erb", /\s(-block)/, " #{name}-block"
23
- gsub_file "app/views/sir_trevor/blocks/_#{name}_block.html.erb", /\s(_block)/, " #{name}_block"
17
+ template "_block.html.erb", "app/views/sir_trevor/blocks/_#{file_name}_block.html.erb"
24
18
 
25
19
  # Copy the BlockDecorator
26
- copy_file "_block.rb", "app/sir_trevor_blocks/#{name}_block.rb"
27
- gsub_file "app/sir_trevor_blocks/#{name}_block.rb", /ExampleBlock/, " #{name}Block"
20
+ template "_block.rb.erb", "app/sir_trevor_blocks/#{file_name}_block.rb"
21
+ end
22
+
23
+ private
28
24
 
25
+ def file_name
26
+ name.underscore
29
27
  end
30
28
 
29
+ def block_name
30
+ file_name.camelize
31
+ end
32
+
33
+ def css_class
34
+ file_name.dasherize
35
+ end
31
36
  end
32
37
  end
33
- end
38
+ end
@@ -1,3 +1,3 @@
1
- <div class="content-block example-block">
2
- <%= example_block %>
3
- </div>
1
+ <div class="content-block <%= css_class %>-block">
2
+ <%%= <%= file_name %>_block %>
3
+ </div>
@@ -4,20 +4,18 @@
4
4
  Author: C J Bell @ madebymany
5
5
  */
6
6
 
7
- SirTrevor.Blocks.Example = (function(){
8
-
7
+ SirTrevor.Blocks.<%= block_name %> = (function(){
9
8
  return SirTrevor.Block.extend({
10
-
11
9
  // String; Names the block
12
10
  // Note – please use underscores when naming
13
11
  // Eg example_block should be ExampleBlock
14
- type: 'example',
12
+ type: '<%= file_name %>',
15
13
 
16
14
  // Function; the title displayed in the toolbar
17
15
  // Can return a translated string (if required)
18
16
  title: function() {
19
17
  // return i18n.t('blocks:example:title');
20
- return "Example";
18
+ return "<%= block_name %>";
21
19
  },
22
20
 
23
21
  // Boolean; show this blockType of the toolbar
@@ -200,4 +198,4 @@ SirTrevor.Blocks.Example = (function(){
200
198
  }
201
199
  });
202
200
 
203
- })();
201
+ })();
@@ -0,0 +1,2 @@
1
+ class <%= block_name %>Block < SirTrevorRails::Block
2
+ end
@@ -2,26 +2,37 @@ require 'ostruct'
2
2
 
3
3
  module SirTrevorRails
4
4
  class Block < OpenStruct
5
+ DEFAULT_FORMAT = :markdown
5
6
 
6
7
  def self.from_hash(hash, parent)
7
- hash = hash.deep_dup
8
+ hash = hash.deep_dup.with_indifferent_access
8
9
  self.type_klass(hash).new(hash, parent)
9
10
  end
10
11
 
12
+ def format
13
+ send(:[], :format).present? ? send(:[], :format).to_sym : DEFAULT_FORMAT
14
+ end
15
+
11
16
  def initialize(hash, parent)
12
- @as_json = hash
17
+ @raw_data = hash
13
18
  @parent = parent
14
19
  @type = hash[:type].to_sym
15
-
16
20
  super(hash[:data])
17
21
  end
18
22
 
19
- attr_reader :parent, :type, :as_json
23
+ attr_reader :parent, :type
20
24
 
21
25
  def to_partial_path
22
26
  "sir_trevor/blocks/" << self.class.name.demodulize.underscore
23
27
  end
24
28
 
29
+ def as_json(*attrs)
30
+ {
31
+ type: @type.to_s,
32
+ data: marshal_dump
33
+ }
34
+ end
35
+
25
36
  private
26
37
 
27
38
  # Infers the block class.
@@ -58,6 +69,5 @@ module SirTrevorRails
58
69
  self
59
70
  end
60
71
  end
61
-
62
72
  end
63
73
  end
@@ -1,11 +1,23 @@
1
1
  module SirTrevorRails
2
2
  class BlockArray < Array
3
3
 
4
- def self.from_json(str, parent = nil)
5
- blocks = MultiJson.load(str, symbolize_keys: true)
6
- blocks = blocks[:data] if blocks.is_a?(Hash)
7
- blocks.map! { |block_obj| SirTrevorRails::Block.from_hash(block_obj, parent) }
8
- new blocks
4
+ def self.from_json(blocks, parent = nil)
5
+ if blocks.is_a?(String)
6
+ blocks = MultiJson.load(blocks, symbolize_keys: true)
7
+ end
8
+
9
+ if blocks.is_a?(Hash)
10
+ blocks = blocks[:data] || blocks['data'] or
11
+ raise IndexError, "No block data found"
12
+ end
13
+
14
+ new blocks.map { |obj|
15
+ SirTrevorRails::Block.from_hash(obj.deep_symbolize_keys, parent)
16
+ }
17
+ end
18
+
19
+ def to_s
20
+ {data: as_json}.to_json
9
21
  end
10
22
 
11
23
  def has_block_of_type?(type)
@@ -25,11 +25,13 @@ module SirTrevorRails
25
25
  "@" << screen_name
26
26
  end
27
27
 
28
- def profile_image_url(size="bigger")
29
- "//twitter.com/api/users/profile_image/" << self.user[:screen_name] <<
30
- "?size=" << size
28
+ def profile_image_url
29
+ # TODO: add support for different size images: https://dev.twitter.com/overview/general/user-profile-images-and-banners
30
+
31
+ # Split the URL to omit the protocol and let the browser define the context (note: assumes asset is available over both HTTP and HTTPS)
32
+ "//" << self.user[:profile_image_url].split("://")[1]
31
33
  end
32
34
 
33
35
  end
34
36
  end
35
- end
37
+ end
@@ -2,15 +2,34 @@ module SirTrevorRails
2
2
  module Helpers
3
3
  module ViewHelper
4
4
  extend ActiveSupport::Concern
5
+ included do
6
+ include ActionView::Helpers::SanitizeHelper
7
+ end
8
+
9
+ def sir_trevor_format(text, format: :markdown)
10
+ if format.to_s.to_sym == :html
11
+ sir_trevor_html(text)
12
+ else
13
+ sir_trevor_markdown(text)
14
+ end
15
+ end
16
+
17
+ def sir_trevor_html(text)
18
+ sanitize(text, tags: %w(b i a br p))
19
+ end
5
20
 
6
21
  def sir_trevor_markdown(text)
7
- Redcarpet::Render::HTML.new(hard_wrap: true, filter_html: true,
22
+ rndr = CustomMarkdownFormatter.new(hard_wrap: true, filter_html: true,
8
23
  autolink: true, no_intraemphasis: true,
9
24
  fenced_code: true)
10
25
 
11
- markdown = Redcarpet::Markdown.new(CustomMarkdownFormatter)
26
+ markdown = Redcarpet::Markdown.new(rndr)
12
27
  markdown.render(text).html_safe
13
28
  end
29
+
30
+ def without_p_wrap(html)
31
+ Regexp.new('^<p>(.*)<\/p>$').match(html)[1].html_safe rescue html
32
+ end
14
33
  end
15
34
  end
16
35
  end
@@ -1,3 +1,3 @@
1
1
  module SirTrevorRails
2
- VERSION = "0.5.0b1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -5,9 +5,9 @@ module SirTrevorRails
5
5
  super("app/views")
6
6
  end
7
7
 
8
- def find_templates(name, prefix, partial, details)
9
- super(name, prefix.gsub(/^(.)+(sir_trevor)/, '\2'), partial, details)
8
+ def find_templates(name, prefix, *args)
9
+ super(name, prefix.gsub(/^(.)+(sir_trevor)/, '\2'), *args)
10
10
  end
11
11
 
12
12
  end
13
- end
13
+ end
@@ -31,9 +31,11 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "pry-rails"
32
32
  spec.add_development_dependency "combustion"
33
33
  spec.add_development_dependency "sqlite3"
34
+ spec.add_development_dependency "capybara"
35
+ spec.add_development_dependency "launchy"
34
36
 
35
- spec.add_dependency "rails"
37
+ spec.add_dependency "rails", ">= 3", "< 5"
36
38
  spec.add_dependency "redcarpet", ">= 2.0.1", "< 4"
37
39
  spec.add_dependency "twitter-text", "~> 1.4"
38
-
40
+ spec.add_dependency 'multi_json', '~> 1.0'
39
41
  end
@@ -0,0 +1,7 @@
1
+ {
2
+ "type": "custom",
3
+ "data": {
4
+ "text": "Body",
5
+ "title": "Name"
6
+ }
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "type": "heading",
3
+ "data": {
4
+ "text": "Heading <i>1</i>",
5
+ "format": "html"
6
+ }
7
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "heading",
3
+ "data": {
4
+ "text": "Heading _1_"
5
+ }
6
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "type":"image",
3
+ "data":{
4
+ "id":1,
5
+ "updated_at":"2015-01-01T01:00:00+01:00",
6
+ "created_at":"2015-01-01T01:00:00+01:00",
7
+ "file":{
8
+ "url":"http://placeimg.com/1000/600/any",
9
+ "thumb":{
10
+ "url":"http://placeimg.com/100/100/any"
11
+ },
12
+ "large":{
13
+ "url":"http://placeimg.com/800/400/any"
14
+ },
15
+ "xlarge":{
16
+ "url":"http://placeimg.com/1000/600/any"
17
+ },
18
+ "medium":{
19
+ "url":"http://placeimg.com/600/300/any"
20
+ },
21
+ "mobile":{
22
+ "url":"http://placeimg.com/800/400/any"
23
+ }
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "type": "list",
3
+ "data": {
4
+ "listItems": [
5
+ { "content": "List Item 1" },
6
+ { "content": "<b>List Item 2</b>" }
7
+ ],
8
+ "format": "html"
9
+ }
10
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "list",
3
+ "data": {
4
+ "text": " - List Item 1\n - **List Item 2**\n"
5
+ }
6
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "type": "quote",
3
+ "data": {
4
+ "text": "This is quoted text",
5
+ "cite": "Author",
6
+ "format": "html"
7
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "type": "quote",
3
+ "data": {
4
+ "text": "> This is quoted text",
5
+ "cite": "Author"
6
+ }
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "type": "text",
3
+ "data": {
4
+ "text": "One <i>two</i> <b>three</b> <a href='http://example.com'>four</a>",
5
+ "format": "html"
6
+ }
7
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "text",
3
+ "data": {
4
+ "text": "One _two_ **three** [four](http://example.com)"
5
+ }
6
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "type":"tweet",
3
+ "data":{
4
+ "user":{
5
+ "profile_image_url":"http://pbs.twimg.com/profile_images/613336689893896192/5nQjxG2o_normal.jpg",
6
+ "profile_image_url_https":"https://pbs.twimg.com/profile_images/613336689893896192/5nQjxG2o_normal.jpg",
7
+ "screen_name":"SachseInTheCity",
8
+ "name":"Nelson Sachse"
9
+ },
10
+ "id":"615846875078504448",
11
+ "text":"There's no pain without some gain !\n\nlet's run \\o/",
12
+ "created_at":"Tue Jun 30 11:38:31 +0000 2015",
13
+ "entities":{
14
+ "hashtags":[],
15
+ "symbols":[],
16
+ "user_mentions":[],
17
+ "urls":[]
18
+ },
19
+ "status_url":"https://twitter.com/SachseInTheCity/status/615846875078504448"
20
+ }
21
+ }
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ class EditingSpec < ActionDispatch::IntegrationTest
4
+ describe 'Edit form' do
5
+ let(:post) { Post.create(body: blocks_json(:text_html)) }
6
+
7
+ it 'serializes BlockArray to correct json' do
8
+ visit edit_post_path(post)
9
+ expect { find_field('Body').value == {data: post.body.as_json}.to_json }
10
+ end
11
+
12
+ it 'serializes empty BlockArray to empty array json' do
13
+ post = Post.create()
14
+
15
+ visit edit_post_path(post)
16
+ expect { find_field('Body').value == "{\"data\":[]}" }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ class RenderingSpec < ActionDispatch::IntegrationTest
4
+ describe 'SirTrevorContent rendering' do
5
+ it 'renders all blocks as separate divs' do
6
+ post = Post.create(body: blocks_json(:list_html, :text_html))
7
+ visit post_path(post)
8
+
9
+ expect { all('.st__content-block').length == 2 }
10
+ end
11
+ end
12
+
13
+ describe 'Text block' do
14
+ it 'renders markdown format' do
15
+ create_and_visit(blocks_json(:text_markdown))
16
+
17
+ expect { find_block(:text).text == "One two three four" }
18
+ expect { find_block(:text).find('em').text == "two" }
19
+ expect { find_block(:text).find('strong').text == "three" }
20
+ expect { find_block(:text).find('a').text == "four" }
21
+ end
22
+
23
+ it 'renders html format' do
24
+ create_and_visit(blocks_json(:text_html))
25
+
26
+ expect { find_block(:text).text == "One two three four" }
27
+ expect { find_block(:text).find('i').text == "two" }
28
+ expect { find_block(:text).find('b').text == "three" }
29
+ expect { find_block(:text).find('a').text == "four" }
30
+ end
31
+ end
32
+
33
+ describe 'List block' do
34
+ it 'renders markdown format' do
35
+ create_and_visit(blocks_json(:list_markdown))
36
+
37
+ expect { find_block(:list).text == "List Item 1 List Item 2" }
38
+ expect { find_block(:list).all('li').first.text == "List Item 1" }
39
+ expect { find_block(:list).all('li').last.text == "List Item 2" }
40
+ expect { find_block(:list).first('strong').text == "List Item 2" }
41
+ end
42
+
43
+ it 'renders html format' do
44
+ create_and_visit(blocks_json(:list_html))
45
+
46
+ expect { find_block(:list).text == "List Item 1 List Item 2" }
47
+ expect { find_block(:list).all('li').first.text == "List Item 1" }
48
+ expect { find_block(:list).all('li').last.text == "List Item 2" }
49
+ expect { find_block(:list).first('b').text == "List Item 2" }
50
+ end
51
+ end
52
+
53
+ describe 'Image block' do
54
+ it 'renders correctly' do
55
+ create_and_visit(blocks_json(:image))
56
+ expect { find_block(:image).find("img")[:src] == "http://placeimg.com/1000/600/any" }
57
+ end
58
+ end
59
+
60
+ describe 'Heading block' do
61
+ it 'renders markdown format' do
62
+ create_and_visit(blocks_json(:heading_markdown))
63
+
64
+ expect { find_block(:heading).text == "Heading 1" }
65
+ expect { find_block(:heading).find('em').text == "1" }
66
+ end
67
+
68
+ it 'renders html format' do
69
+ create_and_visit(blocks_json(:heading_html))
70
+
71
+ expect { find_block(:heading).text == "Heading 1" }
72
+ expect { find_block(:heading).find('i').text == "1" }
73
+ end
74
+ end
75
+
76
+ describe 'Quote block' do
77
+ it 'renders markdown format' do
78
+ create_and_visit(blocks_json(:quote_markdown))
79
+
80
+ expect { find_block(:quote).find('blockquote').text == "This is quoted text" }
81
+ expect { find_block(:quote).find('cite').text == "– Author" }
82
+ end
83
+
84
+ it 'renders html format' do
85
+ create_and_visit(blocks_json(:quote_html))
86
+
87
+ expect { find_block(:quote).find('blockquote').text == "This is quoted text" }
88
+ expect { find_block(:quote).find('cite').text == "– Author" }
89
+ end
90
+ end
91
+
92
+ describe 'Tweet block' do
93
+ it 'renders correctly' do
94
+ create_and_visit(blocks_json(:tweet))
95
+ expect { find_block(:tweet).all('a')[0][:href] == "//twitter.com/SachseInTheCity" }
96
+ expect { find_block(:tweet).find('img')[:src] == "//pbs.twimg.com/profile_images/613336689893896192/5nQjxG2o_normal.jpg" }
97
+
98
+ expect { find_block(:tweet).find('p').text == "There's no pain without some gain ! let's run \\o/" }
99
+
100
+ expect { find_block(:tweet).find('cite').text == "From @SachseInTheCity on Twitter:" }
101
+
102
+ expect { find_block(:tweet).all('a')[1][:href] == "//twitter.com/SachseInTheCity" }
103
+ expect { find_block(:tweet).all('a')[1].text == "@SachseInTheCity" }
104
+
105
+ expect { find_block(:tweet).find('time')[:datetime] == "Tue Jun 30 11:38:31 +0000 2015" }
106
+ expect { find_block(:tweet).find('time').text == "(#{Time.zone.parse("Tue Jun 30 11:38:31 +0000 2015")})" }
107
+
108
+ expect { find_block(:tweet).all('a')[2][:href] == "https://twitter.com/SachseInTheCity/status/615846875078504448" }
109
+ expect { find_block(:tweet).all('a')[2].text == Time.zone.parse("Tue Jun 30 11:38:31 +0000 2015").to_s }
110
+ end
111
+ end
112
+
113
+ def create_and_visit(json)
114
+ post = Post.create(body: json)
115
+ visit post_path(post)
116
+ end
117
+
118
+ def find_block(type)
119
+ first(".st__content-block--#{type}")
120
+ end
121
+ end
@@ -0,0 +1,33 @@
1
+ class PostsController < ActionController::Base
2
+ def new
3
+ @post = Post.new
4
+ end
5
+
6
+ def edit
7
+ @post = Post.find(params[:id])
8
+ end
9
+
10
+ def create
11
+ @post = Post.new(post_attributes)
12
+
13
+ if @post.save
14
+ redirect_to post_show_path(@post)
15
+ else
16
+ render :new
17
+ end
18
+ end
19
+
20
+ def update
21
+ @post = Post.find(params[:id])
22
+
23
+ if @post.update_attributes(post_attributes)
24
+ redirect_to post_show_path(@post)
25
+ else
26
+ render :edit
27
+ end
28
+ end
29
+
30
+ def show
31
+ @post = Post.find(params[:id])
32
+ end
33
+ end
@@ -1,2 +1,4 @@
1
1
  class Post < ActiveRecord::Base
2
+ include SirTrevorRails::HasSirTrevorContent
3
+ sir_trevor_content :body
2
4
  end
@@ -0,0 +1,3 @@
1
+ <%= form.label :body %>
2
+ <%= form.text_area :body %>
3
+ <%= form.submit :save %>
@@ -0,0 +1,3 @@
1
+ <%= form_for @post do |form| %>
2
+ <%= render form %>
3
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <%= form_for @post do |form| %>
2
+ <%= render form %>
3
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= render @post.body %>
@@ -1,3 +1,3 @@
1
1
  Rails.application.routes.draw do
2
- #
2
+ resources :posts
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,18 @@
1
1
  require 'sir_trevor_rails'
2
2
  require 'combustion'
3
+
4
+ Combustion.initialize! :active_record, :action_view do
5
+ config.active_support.test_order = :random
6
+ end
7
+
8
+
9
+ require 'capybara/rails'
3
10
  require 'minitest/autorun'
4
11
  require 'minitest/spec'
5
12
  require 'minitest/pride'
6
13
  require 'wrong/adapters/minitest'
7
14
  require 'pry'
8
15
 
9
- Combustion.initialize! :active_record, :action_view
10
16
 
11
17
  Wrong.config.alias_assert :expect, override: true
12
18
 
@@ -14,3 +20,38 @@ MiniTest::Spec.class_eval do
14
20
  include Wrong::Assert
15
21
  include Wrong::Helpers
16
22
  end
23
+
24
+ module SirTrevorRails::Fixtures
25
+ def blocks_json(*names)
26
+ "[" + names.map { |name| block_json(name) }.join(',') + "]"
27
+ end
28
+
29
+ def block_json(name)
30
+ filename = File.join('fixtures', 'blocks', name.to_s + '.json')
31
+ path = File.expand_path(filename, File.dirname(__FILE__))
32
+
33
+ File.read(path)
34
+ end
35
+
36
+ def block_hash(name)
37
+ MultiJson.load(block_json(name))
38
+ end
39
+
40
+ def blocks_hash(*names)
41
+ MultiJson.load(blocks_json(*names))
42
+ end
43
+ end
44
+
45
+ class ActiveSupport::TestCase
46
+ extend MiniTest::Spec::DSL
47
+ include Wrong::Assert
48
+ include Wrong::Helpers
49
+
50
+ include SirTrevorRails::Fixtures
51
+ include SirTrevorRails # bad, but we don't have to use full class names
52
+ end
53
+
54
+ class ActionDispatch::IntegrationTest
55
+ # Make the Capybara DSL available in all integration tests
56
+ include Capybara::DSL
57
+ end
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- module SirTrevorRails
3
+ class BlockArraySpec < ActiveSupport::TestCase
4
4
  describe BlockArray do
5
5
  describe 'intialization' do
6
6
  subject { BlockArray }
7
- let(:text_block) { {type: 'text', data: {text: 'Lorem ipsum'}} }
8
- let(:heading_block) { {type: 'heading', data: {text: 'Heading 1'}} }
9
7
 
10
8
  it 'can be initialized with an empty JSON array' do
11
9
  array = subject.from_json('[]')
@@ -13,25 +11,37 @@ module SirTrevorRails
13
11
  end
14
12
 
15
13
  it 'can be initialized with multiple block hashes' do
16
- json = [text_block, heading_block].to_json
17
- array = subject.from_json(json)
14
+ array = subject.from_json(blocks_json(:text_html, :heading_html))
18
15
 
19
16
  expect { array.is_a? BlockArray }
20
17
  expect { array.size == 2 }
21
18
  end
19
+
20
+ it 'can be initialized with a hash' do
21
+ ar = subject.from_json({data: blocks_hash(:text_html, :image)})
22
+
23
+ expect { ar.is_a? BlockArray }
24
+ expect { ar.first.type == :text }
25
+ expect { ar.last.type == :image }
26
+ end
27
+
28
+ it 'can be initialized with an array' do
29
+ ar = subject.from_json(blocks_hash(:text_html, :image))
30
+
31
+ expect { ar.is_a? BlockArray }
32
+ expect { ar.first.type == :text }
33
+ expect { ar.last.type == :image }
34
+ end
22
35
  end
23
36
 
24
37
  describe 'instance methods' do
25
- let(:text_block) { {type: 'text', data: {text: 'First text block'}} }
26
- let(:other_text_block) { {type: 'text', data: {text: 'Other text block'}} }
27
- let(:image_block) { {type: 'image', data: {file: {url: 'http://example.com'}}} }
28
- let(:heading_block) { {type: 'heading', data: {text: 'Heading 1'}} }
29
- let(:json) { [image_block, text_block, heading_block, other_text_block].to_json }
38
+ let(:json) { blocks_json :image, :text_html, :heading_html, :text_markdown }
30
39
 
31
40
  subject { BlockArray.from_json(json) }
32
41
 
33
42
  describe 'has_block_of_type?' do
34
43
  it 'can be called with nonexistent block type' do
44
+ # no assert needed, if anything was wrong it would raise an exception
35
45
  subject.has_block_of_type? :nonexistent
36
46
  end
37
47
 
@@ -47,7 +57,7 @@ module SirTrevorRails
47
57
  describe 'first_block_of_type' do
48
58
  it 'returns first block of given type in the array' do
49
59
  block = subject.first_block_of_type(:text)
50
- assert { block.text == 'First text block' }
60
+ assert { block.text.starts_with? "One <i>two</i>" }
51
61
  end
52
62
 
53
63
  it 'returns nil if called with block type not in the array' do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module SirTrevorRails
3
+ class BlockSpec < ActiveSupport::TestCase
4
4
  describe Block do
5
5
  describe '.block_class' do
6
6
  subject { Block }
@@ -46,11 +46,17 @@ module SirTrevorRails
46
46
  end
47
47
 
48
48
  describe 'JSON representation' do
49
- let(:source_hash) { { type: 'test', data: {} } }
50
- let(:block) { Block.from_hash(source_hash, nil) }
49
+ let(:empty_source_hash) { { type: 'test', data: {} } }
50
+ let(:empty_block) { Block.from_hash(empty_source_hash, nil) }
51
+ let(:data_source_hash) { { type: 'test', data: { one: 2, three: 4 } } }
52
+ let(:data_block) { Block.from_hash(data_source_hash, nil) }
51
53
 
52
54
  it 'returns source hash when #as_json is called' do
53
- expect { block.as_json == source_hash }
55
+ expect { empty_block.as_json == empty_source_hash }
56
+ end
57
+
58
+ it 'serializes block data' do
59
+ expect { data_block.as_json == data_source_hash }
54
60
  end
55
61
  end
56
62
 
@@ -4,16 +4,18 @@ require 'spec_helper'
4
4
  # `spec/internal/app/models/custom_block.rb`, just like it would in real
5
5
  # Rails app.
6
6
 
7
- describe CustomBlock do
8
- describe "SirTrevorRails::Block" do
9
- let(:custom_block_hash) { {type: 'custom', data: {text: 'Body', title: 'name'}} }
7
+ class CustomBlockTest < ActiveSupport::TestCase
8
+ describe CustomBlock do
9
+ describe "SirTrevorRails::Block" do
10
+ let(:custom_block_hash) { {type: 'custom', data: {text: 'Body', title: 'name'}} }
10
11
 
11
- it 'initialises class defined in the file' do
12
- block = SirTrevorRails::Block.from_hash(custom_block_hash, nil)
12
+ it 'initialises class defined in the file' do
13
+ block = SirTrevorRails::Block.from_hash(block_hash(:custom), nil)
13
14
 
14
- assert { block.is_a? CustomBlock }
15
- assert { block.respond_to? :upcase_title }
16
- assert { block.upcase_title == "NAME" }
15
+ assert { block.is_a? CustomBlock }
16
+ assert { block.respond_to? :upcase_title }
17
+ assert { block.upcase_title == "NAME" }
18
+ end
17
19
  end
18
20
  end
19
21
  end
@@ -1,15 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- module SirTrevorRails
3
+ class HasSirTrevorContentSpec < ActiveSupport::TestCase
4
4
  describe 'HasSirTrevorContent' do
5
5
  describe 'initialized for body field' do
6
- before do
7
- Post.send(:include, HasSirTrevorContent)
8
- Post.send(:sir_trevor_content, :body)
9
- end
10
-
11
6
  let(:post) { Post.new }
12
- let(:text_block) { {type: 'text', data: {text: 'Lorem ipsum'}} }
13
7
 
14
8
  it 'returns BlockArray for initialised field' do
15
9
  assert { post.body.is_a? BlockArray }
@@ -28,7 +22,7 @@ module SirTrevorRails
28
22
  end
29
23
 
30
24
  it 'returns blocks if field is SirTrevor JSON' do
31
- post.body = [text_block].to_json
25
+ post.body = blocks_json(:text_html)
32
26
 
33
27
  assert { post.body.size == 1 }
34
28
  assert { post.body.first.is_a? Block }
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ module SirTrevorRails
4
+ describe Helpers do
5
+ let(:subject) { Class.new.send(:include, Helpers::ViewHelper).new }
6
+
7
+ describe 'sir_trevor_format' do
8
+ it 'is callable' do
9
+ expect { subject.respond_to? :sir_trevor_format }
10
+ end
11
+
12
+ it 'calls sir_trevor_markdown if format is not provided' do
13
+ subject.stub :sir_trevor_markdown, 'markdown-called' do
14
+ expect { subject.sir_trevor_format('test') == 'markdown-called' }
15
+ end
16
+ end
17
+
18
+ it 'calls sir_trevor_markdown if format == markdown' do
19
+ subject.stub :sir_trevor_markdown, 'markdown-called' do
20
+ expect { subject.sir_trevor_format('test', format: :markdown) == 'markdown-called' }
21
+ end
22
+ end
23
+
24
+ it 'calls sir_trevor_html if format == html' do
25
+ subject.stub :sir_trevor_html, 'html-called' do
26
+ expect { subject.sir_trevor_format('test', format: :html) == 'html-called' }
27
+ end
28
+ end
29
+ end
30
+
31
+ describe 'sir_trevor_html' do
32
+ it 'removes not allowed html tags' do
33
+ html = '<strong><i>Hello<br><a href="http://example.com/">World</a>!</i></strong>'
34
+ escaped_html = "<i>Hello<br><a href=\"http://example.com/\">World</a>!</i>"
35
+ expect { subject.sir_trevor_html(html) != html }
36
+ expect { subject.sir_trevor_html(html) == escaped_html }
37
+ end
38
+ it 'retains formatting html tags' do
39
+ html = '<b><i>Hello<br><a href="http://example.com/">World</a>!</i></b>'
40
+ expect { subject.sir_trevor_html(html) == html }
41
+ end
42
+ end
43
+ end
44
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sir_trevor_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0b1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Sprinz
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-02-25 00:00:00.000000000 Z
14
+ date: 2016-01-28 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -112,19 +112,53 @@ dependencies:
112
112
  - !ruby/object:Gem::Version
113
113
  version: '0'
114
114
  - !ruby/object:Gem::Dependency
115
- name: rails
115
+ name: capybara
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  requirements:
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
120
  version: '0'
121
- type: :runtime
121
+ type: :development
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - ">="
126
126
  - !ruby/object:Gem::Version
127
127
  version: '0'
128
+ - !ruby/object:Gem::Dependency
129
+ name: launchy
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rails
144
+ requirement: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '3'
149
+ - - "<"
150
+ - !ruby/object:Gem::Version
151
+ version: '5'
152
+ type: :runtime
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '3'
159
+ - - "<"
160
+ - !ruby/object:Gem::Version
161
+ version: '5'
128
162
  - !ruby/object:Gem::Dependency
129
163
  name: redcarpet
130
164
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +193,20 @@ dependencies:
159
193
  - - "~>"
160
194
  - !ruby/object:Gem::Version
161
195
  version: '1.4'
196
+ - !ruby/object:Gem::Dependency
197
+ name: multi_json
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - "~>"
201
+ - !ruby/object:Gem::Version
202
+ version: '1.0'
203
+ type: :runtime
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: '1.0'
162
210
  description:
163
211
  email:
164
212
  - andrew@madebymany.co.uk
@@ -170,6 +218,7 @@ extensions: []
170
218
  extra_rdoc_files: []
171
219
  files:
172
220
  - ".gitignore"
221
+ - ".travis.yml"
173
222
  - CHANGELOG
174
223
  - Gemfile
175
224
  - LICENSE.txt
@@ -188,8 +237,8 @@ files:
188
237
  - config/initializers/validators.rb
189
238
  - lib/generators/sir_trevor_rails/block/block_generator.rb
190
239
  - lib/generators/sir_trevor_rails/block/templates/_block.html.erb
191
- - lib/generators/sir_trevor_rails/block/templates/_block.js
192
- - lib/generators/sir_trevor_rails/block/templates/_block.rb
240
+ - lib/generators/sir_trevor_rails/block/templates/_block.js.erb
241
+ - lib/generators/sir_trevor_rails/block/templates/_block.rb.erb
193
242
  - lib/generators/sir_trevor_rails/views/views_generator.rb
194
243
  - lib/sir_trevor_rails.rb
195
244
  - lib/sir_trevor_rails/block.rb
@@ -202,8 +251,26 @@ files:
202
251
  - lib/sir_trevor_rails/version.rb
203
252
  - lib/sir_trevor_rails/view_resolver.rb
204
253
  - sir_trevor_rails.gemspec
254
+ - spec/fixtures/blocks/custom.json
255
+ - spec/fixtures/blocks/heading_html.json
256
+ - spec/fixtures/blocks/heading_markdown.json
257
+ - spec/fixtures/blocks/image.json
258
+ - spec/fixtures/blocks/list_html.json
259
+ - spec/fixtures/blocks/list_markdown.json
260
+ - spec/fixtures/blocks/quote_html.json
261
+ - spec/fixtures/blocks/quote_markdown.json
262
+ - spec/fixtures/blocks/text_html.json
263
+ - spec/fixtures/blocks/text_markdown.json
264
+ - spec/fixtures/blocks/tweet.json
265
+ - spec/integration/editing_spec.rb
266
+ - spec/integration/rendering_spec.rb
267
+ - spec/internal/app/controllers/posts_controller.rb
205
268
  - spec/internal/app/models/custom_block.rb
206
269
  - spec/internal/app/models/post.rb
270
+ - spec/internal/app/views/posts/_form.html.erb
271
+ - spec/internal/app/views/posts/edit.html.erb
272
+ - spec/internal/app/views/posts/new.html.erb
273
+ - spec/internal/app/views/posts/show.html.erb
207
274
  - spec/internal/config/database.yml
208
275
  - spec/internal/config/routes.rb
209
276
  - spec/internal/db/schema.rb
@@ -214,6 +281,7 @@ files:
214
281
  - spec/unit/block_spec.rb
215
282
  - spec/unit/custom_block_spec.rb
216
283
  - spec/unit/has_sir_trevor_content_spec.rb
284
+ - spec/unit/helpers_spec.rb
217
285
  homepage: https://github.com/madebymany/sir-trevor-rails
218
286
  licenses:
219
287
  - MIT
@@ -229,18 +297,36 @@ required_ruby_version: !ruby/object:Gem::Requirement
229
297
  version: '0'
230
298
  required_rubygems_version: !ruby/object:Gem::Requirement
231
299
  requirements:
232
- - - ">"
300
+ - - ">="
233
301
  - !ruby/object:Gem::Version
234
- version: 1.3.1
302
+ version: '0'
235
303
  requirements: []
236
304
  rubyforge_project:
237
- rubygems_version: 2.2.2
305
+ rubygems_version: 2.4.5.1
238
306
  signing_key:
239
307
  specification_version: 4
240
308
  summary: A ruby wrapper for sir trevor content
241
309
  test_files:
310
+ - spec/fixtures/blocks/custom.json
311
+ - spec/fixtures/blocks/heading_html.json
312
+ - spec/fixtures/blocks/heading_markdown.json
313
+ - spec/fixtures/blocks/image.json
314
+ - spec/fixtures/blocks/list_html.json
315
+ - spec/fixtures/blocks/list_markdown.json
316
+ - spec/fixtures/blocks/quote_html.json
317
+ - spec/fixtures/blocks/quote_markdown.json
318
+ - spec/fixtures/blocks/text_html.json
319
+ - spec/fixtures/blocks/text_markdown.json
320
+ - spec/fixtures/blocks/tweet.json
321
+ - spec/integration/editing_spec.rb
322
+ - spec/integration/rendering_spec.rb
323
+ - spec/internal/app/controllers/posts_controller.rb
242
324
  - spec/internal/app/models/custom_block.rb
243
325
  - spec/internal/app/models/post.rb
326
+ - spec/internal/app/views/posts/_form.html.erb
327
+ - spec/internal/app/views/posts/edit.html.erb
328
+ - spec/internal/app/views/posts/new.html.erb
329
+ - spec/internal/app/views/posts/show.html.erb
244
330
  - spec/internal/config/database.yml
245
331
  - spec/internal/config/routes.rb
246
332
  - spec/internal/db/schema.rb
@@ -251,4 +337,4 @@ test_files:
251
337
  - spec/unit/block_spec.rb
252
338
  - spec/unit/custom_block_spec.rb
253
339
  - spec/unit/has_sir_trevor_content_spec.rb
254
- has_rdoc:
340
+ - spec/unit/helpers_spec.rb
@@ -1,2 +0,0 @@
1
- class ExampleBlock < SirTrevorRails::Block
2
- end