Using plugins in Jekyll - ruby-on-rails

I have been using Jekyll for a month or two now, I am also new to Ruby so learning every day.
In my site I want to add the reading time of blog posts, I have found this ruby gem which will let me do it
https://github.com/garethrees/readingtime
I install it in the normal way into my sites root and add the code needed and nothing happens. This isn't a shock because I have no actually link to it in my sites root?
So it my site looks like this html wise
---
layout: default
---
<div class="twelve columns">
<h3>{{ page.title }}</h3>
<span class="date">Wrote by Josh Hornby</span>
<span class="date">Estimated reading time – <%= #article.body.reading_time %> </span>
<br /> <br />
<%= #article.body %>
{{ content }}
</article>
<div class="twitter_button"> <img src="/images/twitter.png" alt="twitter-logo" width="50" height="50" /> </div>
</div>
<div class="four columns">
<h3>Recent Posts</h3>
<p>Find out what else I've been talking about:</p>
{% for post in site.related_posts limit: 10 %}
<ul class="square">
<li><a class="title" style="text-decoration:none;" href="{{post.url}}"><strong>{{ post.title }}</strong></a>
{% endfor %}
</ul>
</div>
Now I'm not shocked that its not working but my question is how to a install the gem so I can access it in my Jekyll file? Do I need to create a _plugin directory and call it from there? Or won't it work as its not a jekyll plugin? In that case I may have a little project writing my own Ruby Jekyll plugin.

As you have surmised, you cannot call arbitrary ruby commands in your html using <%. Instead, you want to write a plugin which defines a Liquid filter. In your html above, you would use the liquid tag to grab the content of the page. You might want to brush up on liquid-for-designers and liquid-for-programmers as well as the Jekyll notes on writing liquid extensions before we dive in, but I'll try to explain.
First, we need to use a Jekyll filter to grab the content of the page, which we will pass to our plugin for analysis. Above you have an #article.body which probably means something to a ruby on rails site, but doesn't mean anything to Jekyll. As you see in the center of your layout file, the content for the page is simply called content. It is pulled in through a Liquid output, indicated by the {{ }}.
In place of the line
<span class="date">Estimated reading time – <%= #article.body.reading_time %> </span>
We want a line that grabs the content and passes it to our plugin:
<span class="date">Estimated reading time – {{ content | readingtime }} </span>
The vertical bar is a filter, meaning pipe content to the function readingtime and include the output. Now we need to write the plugin itself. In the _plugins directory, we create a ruby script following the standard template for a Liquid filter:
require 'readingtime'
module TextFilter
def readingtime(input)
input.reading_time
end
end
Liquid::Template.register_filter(TextFilter)
And save the above as something like readingtime.rb in _plugins. It's kinda self explanatory, but you see this tells ruby to load the gem, and define a filter that takes its input and applies the reading_time function to that string.
A little note: content will pull in the HTML version of the content, not a plain text string. I don't know if the readingtime gem needs a plain text string, but you can of course convert between them using a little extra ruby code. If necessary, that's left as an exercise to the reader (though this might help).

Related

How to scrape a dynamic website with Ruby

I want to scrape a React website that has products with names and descriptions. The HTML structure looks like this:
<h6 class="menu-index-page__item-title" data-reactid=".5c2v.$menuItemContent.0">
<span data-reactid=".5c2v.$menuItemContent.0.1">Product name</span>
</h6>
<p class="menu-index-page__item-desc" data-reactid=".5c2v.$menuItemContent.1">
<span data-reactid=".5c2v.$menuItemContent.1.0">
<span data-reactid=".5c2v.$menuItemContent.1.0.0">
<span data-reactid=".5c2v.$menuItemContent.1.0.0.0:$0">Description line 1</span>
<br data-reactid=".5c2v.$menuItemContent.1.0.0.0:$0br">
<span data-reactid=".5c2v.$menuItemContent.1.0.0.$1">
<span data-reactid=".5c2v.$menuItemContent.1.0.0.$1.0">
<span data-reactid=".5c2v.$menuItemContent.1.0.0.$1.0.0">Description line 2</span>
<span data-reactid=".5c2v.$menuItemContent.1.0.0.$1.0.1">…</span>
</span>
</span>
</span>
</p>
If the description has more or fewer lines, the number of span tags will change, therefore making a XPath search invalid.
The only thing that comes back for each product on each page is:
.$menuItemContent.1.0.0.0:$0
for the first line of the description and
.$menuItemContent.1.0.0.$1.0.0
for the second line of the description.
Could I use a regular expression to grab just this part from the data-reactid attribute?
I am using Nokogiri at the moment.
The prices are more than likely dynamically loaded by a javascript once the webpage has finished displaying.
To be able to scrape dynamically loaded data, you will need to use a library like Watir which is supported by Rails 5.
With Watir, you are able to wait until all scripts are executed and all data is loaded before attempting to scrape the site.

Decipher this XPath expression to get full href attribute

Is there a way I can get the full href attribute (https://studyacer.com/question/audit-and-assurance-services-444592) instead of a partial href? (https://studyacer.com/question/audit-and-) from this markup?
<td class="word-break">
<span class="label label-success">Due in 5 days</span>
<a href="https://studyacer.com/question/hey-greg-here-is-my-hrm522-discussion-444593">
<strong>hey Greg here is my HRM522 discussion</strong></a>
<small>"Auditing of Organizational Ethics and Compliance Programs" Please respond to the following:...
</small>
<br />
<strong>Business > Management</strong>
</td>
The XPath expression I have is this '//td[#class="word-break"]/a/#href' and it's just giving me a partial url.
The site uses absolute urls (if that helps).
Edit: I am using Scrapy to implement a basic crawler. When I run
response.xpath('//td[#class="word-break"]/a/#href')
I get the partial url.
For anyone with a similar issue. Turns out that running
response.xpath('xpath_expression')
gives you a partial url in Scrapy. Especially if the url is a long one.
For the full value use extract() at the end. Like this
response.xpath('xpath_expression').extract()

Rspec/Capybara - how to target data-target attribute inside a span

in my Rails4/rspec app, I need to male Capybara click on a zone that has no formal "link" , using data-target attribute.
html
<div class="info-zone">
<span data-target="#myInfoZone1" class="City" data-toggle="modal">
</span>
</div>
My current attempt at using capyabar fails
describe "modal loads with the right content" do
it "has right text" do
visit actual_page_path(:id => #deal.id)
find("span[data-target='#myInfoZone1']").click
end
I currently get this error
Capybara::ElementNotFound:
Unable to find css "span[data-target='#myInfoZone1']"
How can I make capybara "find" and click on the zone ?
Thanks for your help
EDIT
I found out why capybara is not finding it!
for a reason I can't understand, that is the html output code capybara finds
<!-- city zone -->
<div id="city-zone">
<!--
We gather here the various types of <spans> and load it via javascript
we append it to the the div id=city-zone
-->
</div>
I am using javascript to load inside this div. so when I load the 'page source' i see what's above
but when I go on chrome dev tools, then I see:
<!-- city zone -->
<div id="city-zone">
<div class="info-zone">
<!--
We gather here the various types of <spans> and load it via javascript
we append it to the the div id=city-zone
-->
<span data-target="#myInfoZone1" class="City" data-toggle="modal">
</span>
</div>
</div>
So i guess capybara sees the same thing as I see when I load the page source: no .
how come my javascript which I append does not appear in the html code source?
what to do about it to make capybara work
Capybara's default driver only tests html rendered by your back-end application server. If you want to test pages with front-end javascript as well, you should use a javascript-enabled driver with Capybara.
Luckily, the folks at thoughtbot made a Capybara extension just for that Capybara-webkit You can easily install it in your Gemfile. Follow the instructions here on how to install the gem.
Finally, once you install it, you can enable javascript tests in your feature specs by adding js: true in your features/scenarios as following:
RSpec.feature "test my new feature", js: true do
# my test
end

Multiple html pages using Intel App Framework

So I have an app that I am trying to strip out all of the JQuery Mobile and now use Intel's App Framework. I am having trouble figuring out how to integrate multiple html pages into the app so that I don't have to have all my code in a single file. I tried this:
$.ui.loadContent("page2.html");
but that doesn't seem to work. I get a 'loading content' spinner but nothing seems to happen.
How do I link pages together from different files?
Ok so I have figured it out. The documentation can sometimes be hard to search and there is no search box available on their website right now. But if you go to the quickstart and then then AFUI(on the left) and then panel properties they say:
data-defer="filename.html" - This will load content into the panel
from a remote page/url. This is useful for separating out content into
different files. af.ui.ready is not available until all files are
loaded asynchronously.
So in my index.html file I have something like this:
<div id="afui">
<nav>
<ul class="list">
<li>Post a Lunch</li>
<li>Personal Profile</li>
<li>Select University</li>
</ul>
</nav>
<!--Main View Pages-->
<div class="panel" title="Events" id="event-list_panel" data-defer="event-list.html" data-load="loadMainEventsList"> </div>
<div class="panel" title="Description" id="description_panel" data-defer="description.html" data-load="loadEventDetails"> </div>
<div class="panel" title="Select University" id="select-university_panel" data-defer="select-university.html"> </div>
</div> <!--id="afui"-->
and then I have the details of each page in seperate files. In my mind this does a literal copy/paste, and I haven't found any evidences yet that it isn't just a copy/paste.
Update:
in AF3 data-defer is now data-include

How can I load a div in rails in response to clicks on another div?

I'm very new to Rails (and web) programming, so I'm not even sure what technology I should be looking for for this.
I've downloaded and run through the first five chapters of the Rails tutorial, but now have a very simple request.
On the left hand side of a web page, I will have a table. If the user clicks on an element in that table, I want to have the right hand side of the page show something new.
I already have a page to display the table, viz:
<div class="center hero-unit">
<div class="container">
<h2>2012 Yearly Report</h2>
<div class="row-fluid">
<div class="span12">
<div class="span4">
<table border="1">
</table>
</div>
<div class="span6">
<!-- load stuff here based on what someone clicks on in the table -->
</div>
</div>
</div>
</div>
</div>
And I'm using bootstrap layouts to display everything. I just don't understand how to change the contents of the 'span6' div based on user behavior in 'span4'.
This is a difficult question to answer. It really depends on what kind of data you're trying to display and what sort of interactivity you're looking for.
You don't really provide much information about what you're trying to accomplish, but if I had to guess, you're trying to load data from your database and insert it into an element without leaving the current page. This is what AJAX is for (your tutorial goes into it a bit in chapter 11) and involves a good deal of javascript, which is generally beyond the scope of a server side language like Ruby. Luckily, rails includes helpers for making it easy to include AJAX features into your web application without having to write a lot of javascript (although you'll have to write some).
As an example, suppose your table has a list of articles, and you want to display the contents of an article in a div when its link is clicked on.
First the link:
<%= link_to article.name, article_url(article), :remote => true %>
The remote option tells Rails that it's an AJAX link.
Next, you need to render a javascript template for your article's show action. You'll name it show.js.erb.
Supposing the div you want the data to be loaded into looks like this,
<div id='article-content'></div>
you'll want your show.js.erb to contain the following:
$('#article-content').html("<%=javascript_escape #article.content %>");
This javascript (with embedded ruby) code will be evaluated when one of your remote links is clicked and will replace the content of your div with the article's content.
There is plenty of resources online to give you more information. It looks like railscasts just released an episode on this topic just a week ago. It requires a subscription to view, but is well worth it (especially if you're just starting out).

Resources