polyhoraire 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|