quran 0.0.1

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 (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/quran +87 -0
  3. data/lib/quran.rb +203 -0
  4. data/test/test_quran.rb +64 -0
  5. metadata +49 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3f16d5355bc2fa0ee3f25669659dfb617c96336c
4
+ data.tar.gz: 2f741da1a905f1fd5a549035c1b100e376b4588c
5
+ SHA512:
6
+ metadata.gz: f6696aac44dc080cd13ac4a9a4ab537ffc19a1874261f9224c3123e7f7d48ba25ba08328357eb8c545894addc325887f0c3bbede49e974edb38a55a53ef950b3
7
+ data.tar.gz: 66257e91cd7b2b94aa0aa44bb9955194d87b7ec951bce95b70d13a700c312ea40743d17d528fd377b7b24390986f2c0e995b1f073f62579bc39344ecd8bb2945
data/bin/quran ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'json'
4
+ require 'quran'
5
+
6
+ quran = Quran.new ['en']
7
+
8
+ options = {:find => nil, :juz => nil, :search => nil}
9
+
10
+ first_argument = ARGV[0]
11
+ possible_commands = ['find', 'juz', 'search']
12
+
13
+ def get_chapter_and_verse(val)
14
+ chapter, verse = val.split(":")
15
+ ret = []
16
+
17
+ if not chapter.nil?
18
+ ret << chapter.to_i
19
+ end
20
+
21
+ if not verse.nil? and not chapter.empty?
22
+ ret << verse.to_i
23
+ end
24
+
25
+ ret
26
+ end
27
+
28
+ def get_or_find_arg(options, option)
29
+ val = options[option]
30
+ if options[option].nil?
31
+ second_arg = ARGV[1]
32
+ if not second_arg.nil?
33
+ val = second_arg
34
+ end
35
+ end
36
+
37
+ val
38
+ end
39
+
40
+ parser = OptionParser.new do|opts|
41
+ opts.banner = "Usage: quran [command=['find', 'juz', 'search']] [options]"
42
+
43
+ opts.on('-f', '--find chapter_number:verse_number', 'Find {ChapterNumber}:{VerseNumber}') do |find|
44
+ options[:find] = find;
45
+ end
46
+
47
+ opts.on('-j', '--juz number', 'Juz Number') do |juz|
48
+ options[:juz] = juz;
49
+ end
50
+
51
+ opts.on('-s', '--search term', 'Search term or phrase') do |search|
52
+ options[:search] = search;
53
+ end
54
+
55
+ opts.on('-h', '--help', 'Displays Help') do
56
+ puts opts
57
+ exit
58
+ end
59
+
60
+ if first_argument.nil? or not possible_commands.include? first_argument
61
+ puts opts
62
+ exit
63
+ end
64
+ end
65
+ parser.parse!
66
+
67
+ output = {}
68
+ # Check what first arg is. Depending on that call the appropriate method.
69
+ if first_argument == 'find'
70
+ val = get_or_find_arg(options, 'find')
71
+ chapter, verse = get_chapter_and_verse(val)
72
+
73
+ if chapter and verse
74
+ output = quran.get(chapter, verse)
75
+ elsif chapter
76
+ output = quran.get_chapter(chapter)
77
+ end
78
+
79
+ elsif first_argument == 'juz'
80
+ val = get_or_find_arg(options, 'juz')
81
+ output = quran.juz(val.to_i)
82
+ elsif first_argument == 'search'
83
+ val = get_or_find_arg(options, 'search')
84
+ output = quran.search(val)
85
+ end
86
+
87
+ puts JSON.pretty_generate(output)
data/lib/quran.rb ADDED
@@ -0,0 +1,203 @@
1
+ # The Main Quran class that allows querying.
2
+ #
3
+ # @todo: I eventually want to have a Translator class that can
4
+ # abstract different translations once we can find them. That
5
+ # way, a user can query and retrive different translations and
6
+ # tafsirs of a verse.
7
+ #
8
+ # @author Zohaib Ahmed
9
+ # @since 0.0.1
10
+ class Quran
11
+ require "sqlite3"
12
+
13
+ # Initialize the Quran with the language(s) specified.
14
+ #
15
+ # @param langs [Array]
16
+ #
17
+ # @example
18
+ # quran = Quran.new ['en', 'ar']
19
+ def initialize(langs=['ar'])
20
+ db = SQLite3::Database.new "lib/qurandb"
21
+ db.results_as_hash = true
22
+
23
+ @chapters = construct_dict(db, 'chapters', 'id')
24
+ @languages = {}
25
+ @default_lang = langs[0]
26
+
27
+ possible_langs = ['en', 'ar', 'hi', 'uz', 'ur']
28
+ langs.each do |lang|
29
+ if possible_langs.include? lang
30
+ @languages[lang] = construct_dict(db, lang, 'chapter')
31
+ else
32
+ raise "The language you asked for isn't supported yet."
33
+ end
34
+ end
35
+
36
+ @juz = [
37
+ {:name => "Alif-Lam-Mim", :start_chapter => 1, :start_verse => 1, :end_chapter => 2, :end_verse => 141},
38
+ {:name => "Sayaqūl", :start_chapter => 2, :start_verse => 142, :end_chapter => 2, :end_verse => 252},
39
+ {:name => "Tilka -r-rusul", :start_chapter => 2, :start_verse => 253, :end_chapter => 3, :end_verse => 92},
40
+ {:name => "Lan Tana Lu", :start_chapter => 3, :start_verse => 93, :end_chapter => 4, :end_verse => 23},
41
+ {:name => "W-al-muḥṣanāt", :start_chapter => 4, :start_verse => 24, :end_chapter => 4, :end_verse => 147},
42
+ {:name => "Lā yuẖibbu-llāh", :start_chapter => 4, :start_verse => 148, :end_chapter => 5, :end_verse => 81},
43
+ {:name => "Wa ʾidha samiʿū", :start_chapter => 5, :start_verse => 82, :end_chapter => 6, :end_verse => 110},
44
+ {:name => "Wa law ʾannanā", :start_chapter => 6, :start_verse => 111, :end_chapter => 7, :end_verse => 87},
45
+ {:name => "Qāl al-malāʾ", :start_chapter => 7, :start_verse => 88, :end_chapter => 8, :end_verse => 40},
46
+ {:name => "W-aʿlamū", :start_chapter => 8, :start_verse => 41, :end_chapter => 9, :end_verse => 92},
47
+ {:name => "Yaʾtadhirūna", :start_chapter => 9, :start_verse => 93, :end_chapter => 11, :end_verse => 5},
48
+ {:name => "Wa mā min dābbah", :start_chapter => 11, :start_verse => 6, :end_chapter => 12, :end_verse => 52},
49
+ {:name => "Wa mā ʾubarriʾu", :start_chapter => 12, :start_verse => 53, :end_chapter => 14, :end_verse => 52},
50
+ {:name => "ʾAlif Lām Rāʾ", :start_chapter => 15, :start_verse => 1, :end_chapter => 16, :end_verse => 128},
51
+ {:name => "Subḥāna -lladhi", :start_chapter => 17, :start_verse => 1, :end_chapter => 18, :end_verse => 74},
52
+ {:name => "Qāla ʾa-lam", :start_chapter => 18, :start_verse => 75, :end_chapter => 20, :end_verse => 135},
53
+ {:name => "Aqtaraba li-n-nās", :start_chapter => 21, :start_verse => 1, :end_chapter => 22, :end_verse => 78},
54
+ {:name => "Qad ʾaflaḥa", :start_chapter => 23, :start_verse => 1, :end_chapter => 25, :end_verse => 20},
55
+ {:name => "Wa-qāla -lladhīna", :start_chapter => 25, :start_verse => 21, :end_chapter => 27, :end_verse => 55},
56
+ {:name => "Am-man khalaq", :start_chapter => 27, :start_verse => 56, :end_chapter => 29, :end_verse => 45},
57
+ {:name => "Utlu ma uhiya", :start_chapter => 29, :start_verse => 46, :end_chapter => 33, :end_verse => 30},
58
+ {:name => "Wa-man yaqnut", :start_chapter => 33, :start_verse => 31, :end_chapter => 36, :end_verse => 27},
59
+ {:name => "Wa-mā-liya", :start_chapter => 36, :start_verse => 28, :end_chapter => 39, :end_verse => 31},
60
+ {:name => "Fa-man ʾaẓlamu", :start_chapter => 39, :start_verse => 21, :end_chapter => 41, :end_verse => 46},
61
+ {:name => "ʾIlaihi yuraddu", :start_chapter => 41, :start_verse => 47, :end_chapter => 45, :end_verse => 37},
62
+ {:name => "Ḥāʾ Mīm", :start_chapter => 46, :start_verse => 1, :end_chapter => 51, :end_verse => 30},
63
+ {:name => "Qāla fa-mā khatbukum", :start_chapter => 51, :start_verse => 31, :end_chapter => 57, :end_verse => 29},
64
+ {:name => "Qad samiʿa -llāhu", :start_chapter => 58, :start_verse => 1, :end_chapter => 66, :end_verse => 12},
65
+ {:name => "Tabāraka -lladhi", :start_chapter => 67, :start_verse => 1, :end_chapter => 77, :end_verse => 50},
66
+ {:name => "Fa-man ʾaẓlamu", :start_chapter => 78, :start_verse => 1, :end_chapter => 114, :end_verse => 6}
67
+ ]
68
+
69
+ return
70
+ end
71
+
72
+ # Initialize the Quran with the language(s) specified.
73
+ #
74
+ # @param chapter [String]
75
+ #
76
+ #
77
+ # @example
78
+ # quran = Quran.new ['en', 'ar']
79
+ def get(chapter, verse, lang=@default_lang)
80
+ if verse.nil?
81
+ raise "Verse does not exist."
82
+ end
83
+
84
+ if verse < 1
85
+ raise "Verse does not exist."
86
+ end
87
+
88
+ verses = @languages[lang][chapter]
89
+
90
+ if verses.nil?
91
+ raise "Chapter does not exist"
92
+ end
93
+
94
+ row = verses[verse - 1]
95
+
96
+ if row.nil?
97
+ raise "Verse does not exist."
98
+ end
99
+
100
+ return row
101
+ end
102
+
103
+ # Get the contents of the entire chapter.
104
+ #
105
+ # @param chapter [Integer] the chapter number
106
+ # @param lang [String] the language for the content
107
+ #
108
+ # @return [Array] Array of hashes containing verses in the chapter
109
+ def get_chapter(chapter, lang=@default_lang)
110
+ return @languages[lang][chapter]
111
+ end
112
+
113
+
114
+ # Get the details for a particular Juz
115
+ #
116
+ # @param juz_number [Integer] the juz number
117
+ #
118
+ # @return [Hash] details of the Juz
119
+ def juz(juz_number)
120
+ return @juz[juz_number]
121
+ end
122
+
123
+
124
+ # Return a list of hashes containing the verses that the search term
125
+ # appears in.
126
+ #
127
+ # @todo Add support for other languages here.
128
+ # @todo Find a way to do more of a fuzzy search of a phrase as a term
129
+ # For example, the verse:
130
+ # "Allah does not impose upon any soul a duty but to the extent of its ability"
131
+ # should be returned if the term was "impose any soul"
132
+ #
133
+ # @param term [String] the search term
134
+ # @param lang [String] the language for the content
135
+ #
136
+ # @return [Array] Search results
137
+ def search(term, lang=@default_lang)
138
+ ret = []
139
+ (1..114).each do |chapter|
140
+ verses = get_chapter(chapter, lang)
141
+
142
+ verses.each do |v|
143
+ if v[lang].include? term
144
+ ret << v
145
+ end
146
+ end
147
+ end
148
+
149
+ return ret
150
+ end
151
+
152
+ private
153
+ # Construct a dict from a table in the db. The key is specified in key.
154
+ # The values will be a dict that contains the rest of the columns in the table.
155
+ #
156
+ # @param db [SQLite3]
157
+ # @param table [String]
158
+ # @param key [String]
159
+ #
160
+ # @return [Hash]
161
+ def construct_dict(db, table, key)
162
+ query_str = "SELECT * FROM #{table}"
163
+ final_hash = {}
164
+ db.execute(query_str) do |row|
165
+ hash_key = row[key]
166
+ # get all the values
167
+ vals = {}
168
+ row.keys.each do |other_key|
169
+ # if the other_key is a type string, take it, otherwise ignore.
170
+ if other_key.is_a? String
171
+ vals[other_key] = row[other_key]
172
+ end
173
+ end
174
+
175
+ if final_hash.has_key?(hash_key)
176
+ final_hash[hash_key] << vals
177
+ else
178
+ final_hash[hash_key] = [vals]
179
+ end
180
+ end
181
+ return final_hash
182
+ end
183
+ end
184
+
185
+
186
+ #
187
+ # Extending the Array class.
188
+ #
189
+ # @author [zohaibahmed]
190
+ #
191
+ class Array
192
+ # Search if search value is in string
193
+ # @param search_value [String]
194
+ # @param regex_format = '%s' [String]
195
+ #
196
+ # @return [type] [description]
197
+ def fuzzy_include?(search_value, regex_format = '%s')
198
+ inject(false) do |is_found, array_value|
199
+ is_found or !!(search_value =~ /#{regex_format % array_value}/)
200
+ end
201
+ end
202
+
203
+ end
@@ -0,0 +1,64 @@
1
+ require 'minitest/autorun'
2
+ require 'quran'
3
+
4
+ class QuranTest < MiniTest::Unit::TestCase
5
+ def setup
6
+ @q = Quran.new ['en']
7
+ end
8
+
9
+ def test_get
10
+ # Get Valid Verses
11
+ assert_equal "In the name of Allah, the Beneficent, the Merciful.",
12
+ @q.get(1,1)['en']
13
+
14
+ assert_equal "And when there are present at the division the relatives and the orphans and the needy, give them (something) out of it and speak to them kind words.",
15
+ @q.get(4, 8)['en']
16
+
17
+ # Verse not found
18
+ assert_raises(RuntimeError) {
19
+ @q.get(2, -1)
20
+ }
21
+
22
+ # Chapter not found
23
+ assert_raises(RuntimeError) {
24
+ @q.get(300,200)['en']
25
+ }
26
+ end
27
+
28
+ def test_get_chapter
29
+ assert_equal 7,
30
+ @q.get_chapter(1).length
31
+
32
+ assert_equal nil,
33
+ @q.get_chapter(444)
34
+
35
+ assert_equal nil,
36
+ @q.get_chapter(-2)
37
+ end
38
+
39
+ def test_juz
40
+ assert_equal "Sayaqūl",
41
+ @q.juz(1)[:name]
42
+
43
+ assert_equal 4,
44
+ @q.juz(5)[:start_chapter]
45
+
46
+ assert_equal nil,
47
+ @q.juz(66)
48
+
49
+ # Second last
50
+ assert_equal "Tabāraka -lladhi",
51
+ @q.juz(-2)[:name]
52
+ end
53
+
54
+ def test_search
55
+ assert_equal 15,
56
+ @q.search("happy").length
57
+
58
+ assert_equal 52,
59
+ @q.search("isa").length
60
+
61
+ assert_equal 0,
62
+ @q.search("potatoes").length
63
+ end
64
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quran
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Zohaib Ahmed
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby interface to the Quran.
14
+ email: zohaib@rocketfuse.com
15
+ executables:
16
+ - quran
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/quran.rb
21
+ - test/test_quran.rb
22
+ - bin/quran
23
+ homepage: http://rubygems.org/gems/quran
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.0.14
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Gem for the Quran
47
+ test_files:
48
+ - test/test_quran.rb
49
+ has_rdoc: