al_citations 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: af9ea94e6107053d9429029a5b553b0ef62b5f38cc33a5568c9a8079094e2dd9
4
+ data.tar.gz: eef9ea5a38524303bfb12c2940e8dc24a4d1e3e0972d9083b941f4c0d26e0280
5
+ SHA512:
6
+ metadata.gz: 2c3f0d0cda356b6d7e119b940d85bce3df84ff3a48520fee4602faca59ea2907038be14873838064be8366adbf4a4bc4761b4a19c6d2b1cc4fda2a2b08112027
7
+ data.tar.gz: eb52e22d573395e585b7a75ce6a9e33158a37873135e479a6d04f9c4de2d8bb1ab51a5fb51ba3137efa21becc618aae78984e71c4865a5a54a14b879601fd6ee
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - 2026-02-07
4
+ - Initial gem release.
5
+ - Added Google Scholar and InspireHEP citation count Liquid tags.
6
+ - Synced Google Scholar parsing regex handling with al-folio main.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Maruan Al-Shedivat.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # Al-Citations
2
+
3
+ A Jekyll plugin that allows you to fetch and display citation counts from Google Scholar and InspireHEP in your Jekyll site.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your Jekyll site's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'al_citations'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle install
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ 1. Add the plugin to your site's `_config.yml`:
22
+
23
+ ```yaml
24
+ plugins:
25
+ - al_citations
26
+ ```
27
+
28
+ 2. Use the tags in your templates:
29
+
30
+ For Google Scholar:
31
+ ```liquid
32
+ {% google_scholar_citations scholar_id article_id %}
33
+ ```
34
+
35
+ For InspireHEP:
36
+ ```liquid
37
+ {% inspirehep_citations recid %}
38
+ ```
39
+
40
+ ### Example
41
+
42
+ ```liquid
43
+ Citations: {% google_scholar_citations "YOUR_SCHOLAR_ID" "ARTICLE_ID" %}
44
+ InspireHEP Citations: {% inspirehep_citations "INSPIRE_RECID" %}
45
+ ```
46
+
47
+ ## Development
48
+
49
+ After checking out the repo, run `bundle install` to install dependencies.
50
+
51
+ ## Contributing
52
+
53
+ Bug reports and pull requests are welcome on GitHub.
@@ -0,0 +1,82 @@
1
+ module Helpers
2
+ extend ActiveSupport::NumberHelper
3
+ end
4
+
5
+ module Jekyll
6
+ class GoogleScholarCitationsTag < Liquid::Tag
7
+ Citations = { }
8
+ CITED_BY_REGEX = /Cited by (\d+[,\d]*)/
9
+
10
+ def initialize(tag_name, params, tokens)
11
+ super
12
+ splitted = params.split(" ").map(&:strip)
13
+ @scholar_id = splitted[0]
14
+ @article_id = splitted[1]
15
+
16
+ if @scholar_id.nil? || @scholar_id.empty?
17
+ puts "Invalid scholar_id provided"
18
+ end
19
+
20
+ if @article_id.nil? || @article_id.empty?
21
+ puts "Invalid article_id provided"
22
+ end
23
+ end
24
+
25
+ def render(context)
26
+ article_id = context[@article_id.strip]
27
+ scholar_id = context[@scholar_id.strip]
28
+ article_url = "https://scholar.google.com/citations?view_op=view_citation&hl=en&user=#{scholar_id}&citation_for_view=#{scholar_id}:#{article_id}"
29
+
30
+ begin
31
+ # If the citation count has already been fetched, return it
32
+ if GoogleScholarCitationsTag::Citations[article_id]
33
+ return GoogleScholarCitationsTag::Citations[article_id]
34
+ end
35
+
36
+ # Sleep for a random amount of time to avoid being blocked
37
+ sleep(rand(1.5..3.5))
38
+
39
+ # Fetch the article page
40
+ doc = Nokogiri::HTML(URI.open(article_url, "User-Agent" => "Ruby/#{RUBY_VERSION}"))
41
+
42
+ # Attempt to extract the "Cited by n" string from the meta tags
43
+ citation_count = 0
44
+
45
+ # Look for meta tags with "name" attribute set to "description"
46
+ description_meta = doc.css('meta[name="description"]')
47
+ og_description_meta = doc.css('meta[property="og:description"]')
48
+
49
+ if !description_meta.empty?
50
+ cited_by_text = description_meta[0]['content']
51
+ matches = cited_by_text.match(CITED_BY_REGEX)
52
+
53
+ if matches
54
+ citation_count = matches[1].sub(",", "").to_i
55
+ end
56
+
57
+ elsif !og_description_meta.empty?
58
+ cited_by_text = og_description_meta[0]['content']
59
+ matches = cited_by_text.match(CITED_BY_REGEX)
60
+
61
+ if matches
62
+ citation_count = matches[1].sub(",", "").to_i
63
+ end
64
+ end
65
+
66
+ citation_count = Helpers.number_to_human(citation_count, :format => '%n%u', :precision => 2, :units => { :thousand => 'K', :million => 'M', :billion => 'B' })
67
+
68
+ rescue Exception => e
69
+ # Handle any errors that may occur during fetching
70
+ citation_count = "N/A"
71
+
72
+ # Print the error message including the exception class and message
73
+ puts "Error fetching citation count for #{article_id} in #{article_url}: #{e.class} - #{e.message}"
74
+ end
75
+
76
+ GoogleScholarCitationsTag::Citations[article_id] = citation_count
77
+ return "#{citation_count}"
78
+ end
79
+ end
80
+ end
81
+
82
+ Liquid::Template.register_tag('google_scholar_citations', Jekyll::GoogleScholarCitationsTag)
@@ -0,0 +1,49 @@
1
+ module Helpers
2
+ extend ActiveSupport::NumberHelper
3
+ end
4
+
5
+ module Jekyll
6
+ class InspireHEPCitationsTag < Liquid::Tag
7
+ Citations = { }
8
+
9
+ def initialize(tag_name, params, tokens)
10
+ super
11
+ @recid = params.strip
12
+ end
13
+
14
+ def render(context)
15
+ recid = context[@recid.strip]
16
+ api_url = "https://inspirehep.net/api/literature/?fields=citation_count&q=recid:#{recid}"
17
+
18
+ begin
19
+ # If the citation count has already been fetched, return it
20
+ if InspireHEPCitationsTag::Citations[recid]
21
+ return InspireHEPCitationsTag::Citations[recid]
22
+ end
23
+
24
+ # Fetch the citation count from the API
25
+ uri = URI(api_url)
26
+ response = Net::HTTP.get(uri)
27
+ data = JSON.parse(response)
28
+
29
+ # Extract citation count from the JSON data
30
+ citation_count = data["hits"]["hits"][0]["metadata"]["citation_count"].to_i
31
+
32
+ # Format the citation count for readability
33
+ citation_count = Helpers.number_to_human(citation_count, format: '%n%u', precision: 2, units: { thousand: 'K', million: 'M', billion: 'B' })
34
+
35
+ rescue Exception => e
36
+ # Handle any errors that may occur during fetching
37
+ citation_count = "N/A"
38
+
39
+ # Print the error message including the exception class and message
40
+ puts "Error fetching citation count for #{recid}: #{e.class} - #{e.message}"
41
+ end
42
+
43
+ InspireHEPCitationsTag::Citations[recid] = citation_count
44
+ return "#{citation_count}"
45
+ end
46
+ end
47
+ end
48
+
49
+ Liquid::Template.register_tag('inspirehep_citations', Jekyll::InspireHEPCitationsTag)
@@ -0,0 +1,9 @@
1
+ require 'active_support/all'
2
+ require 'nokogiri'
3
+ require 'open-uri'
4
+ require 'net/http'
5
+ require 'json'
6
+ require 'uri'
7
+
8
+ require 'al_citations/google_scholar'
9
+ require 'al_citations/inspirehep'
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: al_citations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - al-org
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-02-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.9'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.9'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '6.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '8.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '6.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '8.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: nokogiri
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '1.13'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '2.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '1.13'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '2.0'
73
+ - !ruby/object:Gem::Dependency
74
+ name: bundler
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '2.0'
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '3.0'
93
+ - !ruby/object:Gem::Dependency
94
+ name: rake
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '13.0'
100
+ type: :development
101
+ prerelease: false
102
+ version_requirements: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '13.0'
107
+ description: Jekyll plugin extracted from al-folio that provides Liquid tags to fetch
108
+ and render citation counts from Google Scholar and InspireHEP.
109
+ email:
110
+ - dev@al-org.dev
111
+ executables: []
112
+ extensions: []
113
+ extra_rdoc_files: []
114
+ files:
115
+ - CHANGELOG.md
116
+ - LICENSE
117
+ - README.md
118
+ - lib/al_citations.rb
119
+ - lib/al_citations/google_scholar.rb
120
+ - lib/al_citations/inspirehep.rb
121
+ homepage: https://github.com/al-org-dev/al-citations
122
+ licenses:
123
+ - MIT
124
+ metadata:
125
+ allowed_push_host: https://rubygems.org
126
+ homepage_uri: https://github.com/al-org-dev/al-citations
127
+ source_code_uri: https://github.com/al-org-dev/al-citations
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '2.7'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.0.3.1
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Citation count tags for Google Scholar and InspireHEP
147
+ test_files: []