polyhoraire 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.
- data/Readme.rdoc +13 -0
- data/bin/polyhoraire +98 -0
- data/lib/google.atom.xsl +228 -0
- data/lib/google.xml.xsl +189 -0
- data/lib/google_exporter.rb +125 -0
- data/lib/html.xsl +256 -0
- data/lib/polyhoraire.rb +46 -0
- data/lib/polyhoraire/auth.rb +106 -0
- data/lib/polyhoraire/course.rb +41 -0
- data/lib/polyhoraire/period.rb +69 -0
- data/lib/polyhoraire/poly2XML.xsl +202 -0
- data/lib/polyhoraire/schedule.rb +55 -0
- data/lib/polyhoraire/trimester.rb +98 -0
- data/lib/setup.rb +25 -0
- data/test/asset/schedule.xml +115 -0
- data/test/polyhoraire/test_auth.rb +21 -0
- data/test/polyhoraire/test_course.rb +25 -0
- data/test/polyhoraire/test_period.rb +21 -0
- data/test/polyhoraire/test_schedule.rb +32 -0
- data/test/polyhoraire/test_trimester.rb +75 -0
- data/test/test_google_exporter.rb +29 -0
- data/test/ts_offline.rb +7 -0
- data/test/ts_online.rb +3 -0
- metadata +70 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'polyhoraire'
|
2
|
+
require 'polyhoraire/period'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
class Poly::Course
|
6
|
+
@periodes = Hash.new
|
7
|
+
attr_reader :acronym, :name, :professor, :group, :labGroup, :creditNbr, :periods
|
8
|
+
attr_writer :acronym, :name, :professor, :group, :labGroup, :creditNbr
|
9
|
+
|
10
|
+
def self.from_nokogiri(doc)
|
11
|
+
courses = Array.new
|
12
|
+
|
13
|
+
nodeSet = doc.xpath("//cour")
|
14
|
+
nodeSet.each do |node|
|
15
|
+
course = self.new
|
16
|
+
|
17
|
+
course.acronym = node.attribute("sigle").text
|
18
|
+
course.name = node.xpath("nom").text
|
19
|
+
course.professor = node.xpath("prof").text
|
20
|
+
course.group = node.xpath("groupeTheorie").text
|
21
|
+
course.labGroup = node.xpath("groupeLaboratoire").text
|
22
|
+
course.creditNbr = node.xpath("nombreCredits").text
|
23
|
+
|
24
|
+
course.addPeriods(doc)
|
25
|
+
|
26
|
+
courses.push(course)
|
27
|
+
end
|
28
|
+
return courses
|
29
|
+
end
|
30
|
+
|
31
|
+
def addPeriods (xml)
|
32
|
+
@periods = Poly::Period.from_nokogiri(xml,@acronym)
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
name + '\n' +
|
37
|
+
'\t\t - Professeur : ' + professor + '\n' +
|
38
|
+
'\t\t - Groupe cours : ' + group + '\n' +
|
39
|
+
'\t\t - Groupe lab : ' + labGroup
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'polyhoraire'
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
class Poly::Period
|
6
|
+
include Poly
|
7
|
+
attr_reader :from, :to,:week, :weekDay, :group, :location, :isLab
|
8
|
+
|
9
|
+
def initialize(from,to,week,weekDay,group,location,isLab)
|
10
|
+
@from = from
|
11
|
+
@to = to
|
12
|
+
@week = week
|
13
|
+
@weekDay = weekDay
|
14
|
+
@group = group
|
15
|
+
@location = location
|
16
|
+
@isLab = isLab
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_nokogiri(doc, acronym)
|
20
|
+
nodeSet = doc.xpath("//evenement[sigle = '" + acronym + "']")
|
21
|
+
if nodeSet.nil? || nodeSet.empty?
|
22
|
+
raise ArgumentError
|
23
|
+
else
|
24
|
+
periods = Array.new
|
25
|
+
nodeSet.each do |node|
|
26
|
+
periods.push self.parse_node(node)
|
27
|
+
end
|
28
|
+
|
29
|
+
return periods
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def dates(trimester,week,day)
|
34
|
+
return @trimester.week[week][day]
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
puts "---"
|
39
|
+
puts "From : " + @from + " To : " + @to + " On day : " + @weekDay
|
40
|
+
puts "---"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def self.parse_node(node)
|
46
|
+
moment = node.xpath("moment")
|
47
|
+
|
48
|
+
from = moment.attribute('debut').text
|
49
|
+
to = moment.attribute('fin').text
|
50
|
+
week = extractWeek(moment.attribute('semaine').text)
|
51
|
+
weekDay = moment.attribute('jour').text.to_i
|
52
|
+
group = node.xpath("groupe").text
|
53
|
+
location = node.xpath("local").text
|
54
|
+
isLab = node.attribute("type").text == "lab"
|
55
|
+
|
56
|
+
self.new(from,to,week,weekDay,group,location,isLab)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.extractWeek(string)
|
60
|
+
case string
|
61
|
+
when 'B1'
|
62
|
+
return 1
|
63
|
+
when 'B2'
|
64
|
+
return 2
|
65
|
+
else
|
66
|
+
return 0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xsl:stylesheet version="1.0"
|
3
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
4
|
+
xmlns:str="http://exslt.org/strings"
|
5
|
+
xmlns:exslt="http://exslt.org/common"
|
6
|
+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
|
7
|
+
exclude-result-prefixes="str fn exslt">
|
8
|
+
|
9
|
+
|
10
|
+
<!-- Pour la transformation d'identidees -->
|
11
|
+
<xsl:template>
|
12
|
+
<xsl:call-template name="IdentityTransform"/>
|
13
|
+
</xsl:template>
|
14
|
+
|
15
|
+
<xsl:template name="IdentityTransform">
|
16
|
+
<xsl:copy>
|
17
|
+
<xsl:apply-templates select="@*|node()"/>
|
18
|
+
</xsl:copy>
|
19
|
+
</xsl:template>
|
20
|
+
|
21
|
+
<xsl:template match="/">
|
22
|
+
<poly>
|
23
|
+
<informations>
|
24
|
+
<xsl:for-each select="html/body/center/table[2]/tr/td/table/tr[position() > 1 and position() < last()]">
|
25
|
+
<xsl:element name="cour">
|
26
|
+
<xsl:attribute name="sigle"><xsl:value-of select="normalize-space(td)"/></xsl:attribute>
|
27
|
+
<nom><xsl:value-of select="normalize-space(td[2]/node())"/></nom>
|
28
|
+
<prof><xsl:value-of select="normalize-space(td[2]/node()[last()])"/></prof>
|
29
|
+
<groupeTheorie><xsl:value-of select="normalize-space(td[3])"/></groupeTheorie>
|
30
|
+
<groupeLaboratoire><xsl:value-of select="normalize-space(td[4])"/></groupeLaboratoire>
|
31
|
+
<nombreCredits><xsl:value-of select="normalize-space(td[5])"/></nombreCredits>
|
32
|
+
</xsl:element>
|
33
|
+
</xsl:for-each>
|
34
|
+
</informations>
|
35
|
+
<horaire>
|
36
|
+
<xsl:call-template name="tJournee"> <xsl:with-param name="numero" select="1"/> </xsl:call-template>
|
37
|
+
<xsl:call-template name="tJournee"> <xsl:with-param name="numero" select="2"/> </xsl:call-template>
|
38
|
+
<xsl:call-template name="tJournee"> <xsl:with-param name="numero" select="3"/> </xsl:call-template>
|
39
|
+
<xsl:call-template name="tJournee"> <xsl:with-param name="numero" select="4"/> </xsl:call-template>
|
40
|
+
<xsl:call-template name="tJournee"> <xsl:with-param name="numero" select="5"/> </xsl:call-template>
|
41
|
+
</horaire>
|
42
|
+
</poly>
|
43
|
+
</xsl:template>
|
44
|
+
|
45
|
+
<xsl:template name="tJournee">
|
46
|
+
<xsl:param name="numero"/>
|
47
|
+
|
48
|
+
<xsl:variable name="journee">
|
49
|
+
<xsl:for-each select="html/body/center/table[3]/tr/td/table/tr/td[position() = ($numero + 1)]">
|
50
|
+
<xsl:choose>
|
51
|
+
<xsl:when test="./font">
|
52
|
+
<xsl:element name="periode">
|
53
|
+
<xsl:attribute name="heure">
|
54
|
+
<xsl:value-of select="substring-before(string(../td[position()=1]),'h') + 0"/>
|
55
|
+
<xsl:text>:</xsl:text>
|
56
|
+
<xsl:value-of select="substring-after(string(../td[position()=1]),'h') + 0"/>
|
57
|
+
</xsl:attribute>
|
58
|
+
|
59
|
+
<xsl:for-each select="font/node()">
|
60
|
+
<xsl:choose>
|
61
|
+
<xsl:when test="contains(string(.), 'Lab')">
|
62
|
+
<infoSemaine><xsl:call-template name="IdentityTransform"/></infoSemaine>
|
63
|
+
</xsl:when>
|
64
|
+
<xsl:when test="contains(string(.), '(')">
|
65
|
+
<infoCour><xsl:call-template name="IdentityTransform"/></infoCour>
|
66
|
+
</xsl:when>
|
67
|
+
</xsl:choose>
|
68
|
+
</xsl:for-each>
|
69
|
+
</xsl:element>
|
70
|
+
</xsl:when>
|
71
|
+
|
72
|
+
<xsl:otherwise>
|
73
|
+
<xsl:element name="periode">
|
74
|
+
<xsl:attribute name="heure">
|
75
|
+
<xsl:value-of select="substring-before(string(../td[position()=1]),'h') + 0"/>
|
76
|
+
<xsl:text>:</xsl:text>
|
77
|
+
<xsl:value-of select="substring-after(string(../td[position()=1]),'h') + 0"/>
|
78
|
+
</xsl:attribute>
|
79
|
+
|
80
|
+
<xsl:for-each select="node()">
|
81
|
+
<xsl:choose>
|
82
|
+
<xsl:when test="contains(string(.), 'Lab')">
|
83
|
+
<infoSemaine><xsl:call-template name="IdentityTransform"/></infoSemaine>
|
84
|
+
</xsl:when>
|
85
|
+
<xsl:when test="contains(string(.), '(')">
|
86
|
+
<infoCour><xsl:call-template name="IdentityTransform"/></infoCour>
|
87
|
+
</xsl:when>
|
88
|
+
</xsl:choose>
|
89
|
+
</xsl:for-each>
|
90
|
+
</xsl:element>
|
91
|
+
|
92
|
+
</xsl:otherwise>
|
93
|
+
</xsl:choose>
|
94
|
+
|
95
|
+
|
96
|
+
</xsl:for-each>
|
97
|
+
</xsl:variable>
|
98
|
+
|
99
|
+
<xsl:variable name="heures">
|
100
|
+
<xsl:for-each select="exslt:node-set($journee)">
|
101
|
+
<xsl:for-each select="periode">
|
102
|
+
<xsl:variable name="listeCoursPrecedents">
|
103
|
+
<xsl:for-each select="preceding-sibling::periode[1]/infoCour">
|
104
|
+
<xsl:value-of select="."/>
|
105
|
+
</xsl:for-each>
|
106
|
+
</xsl:variable>
|
107
|
+
<xsl:for-each select="./infoCour">
|
108
|
+
<xsl:choose>
|
109
|
+
<xsl:when test="not(contains(string($listeCoursPrecedents),string(.)))">
|
110
|
+
<xsl:element name="debut">
|
111
|
+
|
112
|
+
<xsl:choose>
|
113
|
+
<xsl:when test="following-sibling::*[1 and name()='infoSemaine']">
|
114
|
+
<xsl:attribute name="type">lab</xsl:attribute>
|
115
|
+
<xsl:attribute name="semaine">
|
116
|
+
<xsl:choose>
|
117
|
+
<xsl:when test="contains(string(following-sibling::*[1 and name()='infoSemaine']),'B1')">B1</xsl:when>
|
118
|
+
<xsl:when test="contains(string(following-sibling::*[1 and name()='infoSemaine']),'B2')">B2</xsl:when>
|
119
|
+
</xsl:choose>
|
120
|
+
</xsl:attribute>
|
121
|
+
</xsl:when>
|
122
|
+
<xsl:otherwise>
|
123
|
+
<xsl:attribute name="type">cours</xsl:attribute>
|
124
|
+
</xsl:otherwise>
|
125
|
+
</xsl:choose>
|
126
|
+
|
127
|
+
<xsl:attribute name="cour"><xsl:value-of select="str:tokenize(.)"/></xsl:attribute>
|
128
|
+
<xsl:attribute name="groupe"><xsl:value-of select="substring(string(str:tokenize(string(.))[2]),2,2)"/></xsl:attribute>
|
129
|
+
<xsl:attribute name="local"><xsl:value-of select="str:tokenize(.)[3]"/></xsl:attribute>
|
130
|
+
<xsl:attribute name="heure"><xsl:value-of select="../@heure"/></xsl:attribute>
|
131
|
+
</xsl:element>
|
132
|
+
</xsl:when>
|
133
|
+
</xsl:choose>
|
134
|
+
</xsl:for-each>
|
135
|
+
|
136
|
+
<xsl:variable name="listeCoursSuivants">
|
137
|
+
<xsl:for-each select="following-sibling::periode[1]/infoCour">
|
138
|
+
<xsl:value-of select="."/>
|
139
|
+
</xsl:for-each>
|
140
|
+
</xsl:variable>
|
141
|
+
|
142
|
+
<xsl:for-each select="./infoCour">
|
143
|
+
<xsl:choose>
|
144
|
+
<xsl:when test="not(contains(string($listeCoursSuivants),string(.)))">
|
145
|
+
<xsl:element name="fin">
|
146
|
+
<xsl:attribute name="cour"><xsl:value-of select="str:tokenize(.)"/></xsl:attribute>
|
147
|
+
<xsl:attribute name="groupe"><xsl:value-of select="substring(string(str:tokenize(string(.))[2]),2,2)"/></xsl:attribute>
|
148
|
+
<xsl:attribute name="local"><xsl:value-of select="str:tokenize(.)[3]"/></xsl:attribute>
|
149
|
+
<xsl:attribute name="heure">
|
150
|
+
<xsl:value-of select="substring-before(string(../@heure),':') + 1"/>
|
151
|
+
<xsl:text>:</xsl:text>
|
152
|
+
<xsl:value-of select="substring-after(string(../@heure),':') + 0"/>
|
153
|
+
</xsl:attribute>
|
154
|
+
|
155
|
+
</xsl:element>
|
156
|
+
</xsl:when>
|
157
|
+
</xsl:choose>
|
158
|
+
</xsl:for-each>
|
159
|
+
|
160
|
+
</xsl:for-each>
|
161
|
+
</xsl:for-each>
|
162
|
+
</xsl:variable>
|
163
|
+
|
164
|
+
|
165
|
+
<xsl:for-each select="exslt:node-set($heures)">
|
166
|
+
<xsl:for-each select="./debut">
|
167
|
+
<evenement>
|
168
|
+
<xsl:attribute name="type">
|
169
|
+
<xsl:value-of select="@type"></xsl:value-of>
|
170
|
+
</xsl:attribute>
|
171
|
+
<moment>
|
172
|
+
<xsl:attribute name="semaine">
|
173
|
+
<xsl:value-of select="@semaine"/>
|
174
|
+
</xsl:attribute>
|
175
|
+
<xsl:attribute name="jour">
|
176
|
+
<xsl:value-of select="$numero"/>
|
177
|
+
</xsl:attribute>
|
178
|
+
<xsl:attribute name="debut">
|
179
|
+
<xsl:value-of select="@heure"/>
|
180
|
+
</xsl:attribute>
|
181
|
+
<xsl:attribute name="fin">
|
182
|
+
<xsl:value-of select="following-sibling::fin[@cour = current()/@cour]/@heure"/>
|
183
|
+
</xsl:attribute>
|
184
|
+
</moment>
|
185
|
+
<sigle>
|
186
|
+
<xsl:value-of select="@cour"/>
|
187
|
+
</sigle>
|
188
|
+
<groupe>
|
189
|
+
<xsl:value-of select="@groupe"/>
|
190
|
+
</groupe>
|
191
|
+
<local>
|
192
|
+
<xsl:value-of select="@local"/>
|
193
|
+
</local>
|
194
|
+
</evenement>
|
195
|
+
</xsl:for-each>
|
196
|
+
</xsl:for-each>
|
197
|
+
|
198
|
+
</xsl:template>
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
</xsl:stylesheet>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'polyhoraire'
|
2
|
+
require 'polyhoraire/trimester'
|
3
|
+
require 'polyhoraire/course'
|
4
|
+
|
5
|
+
class Poly::Schedule
|
6
|
+
include Poly
|
7
|
+
attr_reader :trimester
|
8
|
+
|
9
|
+
# Trimesters : Hash of the possible trimesters {:id => :label}
|
10
|
+
# postParams : PostParams obtained from the connection
|
11
|
+
def initialize(auth,trimester)
|
12
|
+
@params = auth.postParams
|
13
|
+
@trimesters = auth.trimesters
|
14
|
+
|
15
|
+
@trimester = Poly::Trimester.fromYAML(trimester)
|
16
|
+
|
17
|
+
get(trimester)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_xml
|
21
|
+
to_xml_doc.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_xml_doc
|
25
|
+
html = @response.body.to_s
|
26
|
+
# Too much spaces, substring-after wont work in some case if their still have trailling character ' '
|
27
|
+
html.gsub!(" ","")
|
28
|
+
|
29
|
+
doc = Nokogiri::HTML(html) do |config|
|
30
|
+
config.noent
|
31
|
+
end
|
32
|
+
|
33
|
+
xsl = Nokogiri::XSLT(File.read(Poly::XSLDocs[:poly2XML]))
|
34
|
+
|
35
|
+
return xsl.transform(doc)
|
36
|
+
end
|
37
|
+
|
38
|
+
def courses
|
39
|
+
doc = to_xml_doc
|
40
|
+
Poly::Course.from_nokogiri(doc)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def get(trimester)
|
46
|
+
raise "Invalid trimester" unless trimesterValid?(trimester)
|
47
|
+
|
48
|
+
@params['trimestre'] = trimester
|
49
|
+
@response = fetch(Poly::URL[:schedule],@params)
|
50
|
+
end
|
51
|
+
|
52
|
+
def trimesterValid?(id)
|
53
|
+
return @trimesters.has_key?(id.to_s)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'polyhoraire'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class Poly::Trimester
|
5
|
+
attr_reader :week, :starts
|
6
|
+
|
7
|
+
DAY_RANGE = (1..5)
|
8
|
+
WEEK_RANGE = (1..2)
|
9
|
+
|
10
|
+
# Create from a YAML file wich is situated in 'conf/trimesters.yaml'
|
11
|
+
def self.fromYAML(trimesterID)
|
12
|
+
config = YAML.load_file(Poly::userConfDir + "/trimesters.yaml")
|
13
|
+
raise ArgumentError, "Invalid trimester : " + trimesterID.to_s unless config.include?(trimesterID)
|
14
|
+
selected = config[trimesterID]
|
15
|
+
|
16
|
+
|
17
|
+
starts = selected['starts']
|
18
|
+
schoolBreak = selected['schoolBreak']
|
19
|
+
ends = selected['ends']
|
20
|
+
holidays = selected['holidays']
|
21
|
+
exceptions = selected['exceptions']
|
22
|
+
|
23
|
+
return self.new(starts, schoolBreak, ends, holidays, exceptions)
|
24
|
+
end
|
25
|
+
|
26
|
+
# period : Period object for wich you want every dates it occurs
|
27
|
+
# Returns the list of dates for the course period
|
28
|
+
def getDates(period)
|
29
|
+
if period.week == 0
|
30
|
+
dates = @week[1][period.weekDay] + @week[2][period.weekDay]
|
31
|
+
return dates.sort
|
32
|
+
end
|
33
|
+
return @week[period.week][period.weekDay].sort
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def initialize(starts, schoolBreak, ends, holidays, exceptions)
|
39
|
+
@starts = starts
|
40
|
+
@schoolBreak = schoolBreak
|
41
|
+
@ends = ends
|
42
|
+
@holidays = holidays
|
43
|
+
@exceptions = exceptions
|
44
|
+
|
45
|
+
@week = Hash.new
|
46
|
+
generateDates
|
47
|
+
end
|
48
|
+
|
49
|
+
def generateDates
|
50
|
+
WEEK_RANGE.each do |w|
|
51
|
+
@week[w] = Hash.new
|
52
|
+
DAY_RANGE.each do |d|
|
53
|
+
@week[w][d] = datesFor(d,w)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def datesFor(day,week)
|
59
|
+
|
60
|
+
raise ArgumentError, "Day not in accepted range" unless DAY_RANGE.cover?(day)
|
61
|
+
raise ArgumentError, "Week not in accepted range" unless WEEK_RANGE.cover?(week)
|
62
|
+
starts = @starts + day-1 + 7*(week-1)
|
63
|
+
|
64
|
+
dates = Array.new
|
65
|
+
dates = datesUntil(starts,@schoolBreak)
|
66
|
+
dates += datesUntil(dates.last + 21,@ends)
|
67
|
+
dates += exceptionDates(day,week)
|
68
|
+
|
69
|
+
return dates
|
70
|
+
end
|
71
|
+
|
72
|
+
def exceptionDates(day,week)
|
73
|
+
dates = Array.new
|
74
|
+
@exceptions.each do |date, changedTo|
|
75
|
+
if changedTo['week'] == 'b' + week.to_s and changedTo['day'] == day
|
76
|
+
dates.push(date)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
return dates
|
81
|
+
end
|
82
|
+
|
83
|
+
def datesUntil(from, to)
|
84
|
+
dates = Array.new
|
85
|
+
|
86
|
+
iDate = from
|
87
|
+
while (iDate <=> to) == -1
|
88
|
+
dates.push(iDate) unless dayChanged?(iDate)
|
89
|
+
iDate += 14
|
90
|
+
end
|
91
|
+
return dates
|
92
|
+
end
|
93
|
+
|
94
|
+
def dayChanged?(date)
|
95
|
+
@exceptions.has_key?(date) or @holidays.include?(date)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|