What's the Best Way to Do Pre-formatted Code Snippets in Slim Templates - slim-lang

I'm trying to display pre-formatted code snippets using Slim templates in my Ruby on Rails app. To be clear, I'm cutting and pasting code samples between <pre><code></code></pre> tags and need them to display with all the proper indentations.
Due to the fact that Slim also makes use of indentations, this makes things awkward. Is there a standard way of doing this?

I've figured it out. I didn't realize multi-line strings could be nested under a single pipe like this:
pre
code
|
# The Greeter class
class Greeter
def initialize(name)
#name = name.capitalize
end
def salute
puts "Hello #{#name}!"
end
end
g = Greeter.new("world")
g.salute

Related

Is it possible to use concerns outside of Rails

I like the idea of ActiveSupport::Concerns but wondering if possible to use in a vanilla Ruby app. Or is it only in a Rails app? I'm thinking of the example using ActiveRecord in a Sinatra app.
Edit
Looks like you can by requiring 'active_support', though I am not sure if any nuance about this doesn't work.
Like:
require 'active_support'
module Printable
include ActiveSupport::Concern
def print
puts "I will print here"
end
end
class User
include Printable
def initialize(name)
#name = name
end
def say_my_name
puts "my name: #{#name}"
end
end
Yes, you can (and it seems like you've discovered how). Much of ActiveSupport is written in a way that it can be added by itself to other projects.
You can even require just Concern with require "active_support/concern"
Opinion
I'm generally against using ActiveSupport::Concern though:
violates Composition Over Inheritance (see Nothing is Something by Sandi Metz)
95% of functionality is provided by vanilla Ruby already, in only 0-3 more lines of code (zero meaning you didn't need Concern at all)
Examples:
The code snippet you've pasted works perfectly fine with a bare Ruby module
Rail's own documentation on Concern explains usage with vanilla Ruby examples of the same length and complexity
In that documentation, it says: "Given a Foo module and a Bar module which depends on the former...", as if you'd want to deal with mixin hell

Liquid filters not working (rails app)

I'm using Liquid as my templating laguage for price tags that users can download from my site.
Liquid works fine alone, however no custom filters work. They simply doesn't do anything.
Here is an example:
$ {{item.primary_offer.subscription.month_price | no_decimal}},- per month
this should result in:
$ 199,- per month.
But the filter does not work so the result is:
$ 199.0,- per month.
My filters file looks like this:
module LiquidFilters
include ActionView::Helpers::NumberHelper
def no_decimal(input)
number_to_currency(input.to_f, precision: 0)
end
end
Liquid::Template.register_filter(LiquidFilters)
and my application helper that renders the liquid input looks like this:
def liquidize(content, arguments)
Liquid::Template.parse(content).render(arguments, :filters => [LiquidFilters])
end
I solved this problem by moving the LiquidFilters module into the applications helper file (under the ApplicationHelper module).
Everything the suddenly worked.
I do not understand why this made a difference but it did work. If anyone can explain this ill upvote their answer. :)

Testing a call to an external library in MiniTest

I am working on an application for a blog using Ruby on Rails. I have a model called Essay with a Draper Decorator. I am also using MiniTest::Spec for testing this application. Each Essay has a body which will be stored as Markdown. In the EssayDecorator, I have a method called body which renders the Markdown to html using RedCarpet.
In order to test this method, I wrote the following code:
describe '#body' do
it 'returns html from the markdown' do
essay = FactoryGirl.create(:essay)
#decorated_essay = essay.decorate
markdown = Minitest::Mock.new
#decorated_essay.stub :markdown, markdown do
markdown.expect :render, "<p>Test</p>", [essay.body]
#decorated_essay.send(:body)
markdown.verify
end
end
end
And inside the decorator I have two methods:
def body
markdown.render(model.body).html_safe
end
def markdown
Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true)
end
This test passes, but seems weird to me. I don't want to test that RedCarpet is doing its job, I just want to test that I call the render method.
Is there a best practice for mocking out this kind of thing in MiniTest? I am pretty new to using Mocks and very new to using MiniTest.
Thanks, in advance.
IMO this code seems weird because it is not testing the behavior of your code, but it is testing the implementation. If the implementation changed (you stored the HTML in a cache instead of running it through Redcarpet) then this test would fail. This looks over-mocked to me.
I don't want to test that RedCarpet is doing its job, I just want to test that I call the render method.
This is implementation. Why are you running the body through markdown? Because you want hyperlinks to be created from URLs? I'd create a test for that. You want to ensure links have the no-follow attribute? I'd create a test for that. Create tests for why the code is doing something, not how it is doing it.
It is also entirely possible you are missing an abstraction in your application. Something that is responsible for formatting the plain text into HTML. Something that uses Redcarpet or RDiscount or any other library deemed important. The EssayDecorator probably shouldn't be responsible for ensuring that the text was formatted properly, but it may be responsible for telling the right object to apply the formatting.

Possible to embed markdown within erb?

If you use haml as rails view template, you can write portion of your page using markdown by using the ":markdown" filter.
Is is possible to do the same using erb?
It's pretty easy to write a method that does it, assuming you're using something like Rails which has #capture, #concat, and #markdown helpers. Here's an example, using Maruku:
def markdown_filter(&block)
concat(markdown(capture(&block)))
end
Then you can use this as so:
<% markdown_filter do %>
# Title
This is a *paragraph*.
This is **another paragraph**.
<% end %>
There are a few things to note here. First, it's important that all the text in the block have no indentation; you could get around this by figuring out the common indentation of the lines and removing it, but I didn't do that in the example helper above. Second, it uses Rails' #markdown helper, which could easily be implemented in other frameworks as so (replacing Maruku with your Markdown processor of choice):
def markdown(text)
Maruku.new(text).to_html
end
Rails 3 has removed the #markdown helper, so just add the above code in the appropriate helper, substituting the Markdown processor of your choice.
ERB does not have filtering like this built-in. You'll need to directly use a gem that handles it, like RDiscount or the venerable BlueCloth.

Ruby on Rails: Modules vs. Classes

I'm trying to add a function that will be accessible throughout all parts of my program. I want something like:
def GlobalFunctions.my_function(x,y)
puts x + y
end
to be accessible for all models. Specifically I am trying to use a function like this in my seeds.rb file but I am most likely going to be reusing the code and don't want any redundancy. Now I know I can make a simple class, but I could also make a module. What are some reasons to go in either direction? And once I've decided on which type to use, how do I make it accessible throughout the whole program?
I have tried a module, but I keep getting " Expected app/[module file] to define [ModuleName]"
You'd define a class for something you'll want to make instances of. In this case, a module would probably be better, as modules basically just group code together:
module GlobalFunctions
def self.my_function(x,y)
puts x+y
end
end
GlobalFunctions.my_function(4,5) # => 9
Alternatively, you could define it on Kernel, and then just call it anywhere. Kernel is where methods like puts are defined.
def Kernel.my_function(x,y)
puts x + y
end
my_function(4,5) # => 9
Adding methods to Kernel (answer from PreciousBodilyFluids) is usually considered a bad smell and can lead to some really hard to find bugs in large projects.
It's much more accepted to relevantly namespace the code and put in to /lib/.
class Formatting
def self.bold(str)
return "<strong>#{str}</strong>"
end
end
You can then:
require 'formatting'
puts Formatting.bold("text")
or
require 'formatting'
include Formatting
puts bold("text")
It'll be clear to anyone who comes to the code later what you're using too. If you're using Rails you won't need the require.
PreciousBodilyFluids is correct, and if this GlobalFunctions is part of a RoR project, you may want to name the file global_functions.rb and place it in the lib/ directory to help you avoid the error message you posted at the end of your question.

Resources