magister_cli 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c679885476aafdf7a4ac673994d31396be72982161a554aebd78ed66b13814ab
4
- data.tar.gz: d762dad23dcfb491ef7295241f663f6da9b310bf441e92f3db7a73043e12c5ce
3
+ metadata.gz: 6e19320505e5f88d8b0e19157fff2e8be5e6c01b24cb1402c4f3cea6bb18e373
4
+ data.tar.gz: a49f14db0b9e983e93faab5f0c3b348556537b22072d19f5b4cd82763af4ecf4
5
5
  SHA512:
6
- metadata.gz: 89799db254ad526cfc7f05370809aa3923d83d9e1aca5f57d3061d18a11ed18f9472b6d5c9c8f32d54a063f68578a6b4dcd1d599189507f45f84658203a74395
7
- data.tar.gz: bbb0d7a439c9d2d37d64222dfaa7eed37fbe92c00a621bb18a069bde8e652971e1d71a392753d5445b481c8424f2e37ed210be42b81314098cfbc190d052bd0e
6
+ metadata.gz: 111c260237f9554a165433d577164749170f2bcac3149cd3f298d604fb6c0b68b78a2d80b2047da79ae9615dcbc4a65f3b141c04062c88c466b9bbef3acd6f18
7
+ data.tar.gz: ce3b825f0507a925e13854f39201562466eb27246e09a1a2fc700db454bec58bf7f9981547ee01091101dbd4e409ff1e6302f1227d60b9755080736505c50c3c
@@ -0,0 +1,9 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+
5
+ class String
6
+ def is_integer?
7
+ self.to_i.to_s == self
8
+ end
9
+ end
@@ -0,0 +1,119 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ require 'magister_cli/tokenizer'
5
+
6
+ class Parser
7
+ @@actions = [
8
+ ['login', ['username', 'password', 'school']],
9
+ ['auth', ['token', 'school']],
10
+ ['quit', []],
11
+ ['exit', []],
12
+ ['get_classes', ['date_from', 'date_to']]
13
+ ]
14
+
15
+ def initialize(string)
16
+ @tokenizer = Tokenizer.new(string)
17
+ @string = string
18
+ end
19
+
20
+ def is_action?(actionName)
21
+ @@actions.each do |action|
22
+ if action[0] == actionName
23
+ return true
24
+ end
25
+ end
26
+ return false
27
+ end
28
+
29
+ def string=(string)
30
+ @string = string
31
+ @tokenizer = Tokenizer.new(string)
32
+ end
33
+
34
+ def get_args(actionName)
35
+ @@actions.each do |action|
36
+ if action[0] == actionName
37
+ return action[1].dup
38
+ end
39
+ end
40
+ end
41
+
42
+ def parse()
43
+ tokens = @tokenizer.tokenize
44
+
45
+ i = 0
46
+
47
+ ast = Array.new
48
+ while i < tokens.length
49
+ tmp = 0
50
+ props = false
51
+ opts = false
52
+ altOpts = false # true if opts are in the place props would be
53
+
54
+ if tokens[0 + i]["type"] != "KEYWORD"
55
+ puts "Current index: #{i.to_s}"
56
+ raise SyntaxError.new "Expected #{tokens[0 + i]["value"]} to be a KEYWORD, is a #{tokens[0 + i]["type"]}"
57
+ end
58
+
59
+ if tokens[1 + i] != nil && tokens[1 + i]["type"] == "PARAMS"
60
+ tmp += 1
61
+ props = true
62
+ end
63
+
64
+ if tokens[2 + i] != nil && tokens[2 + i]["type"] == "OPTIONS"
65
+ tmp += 1
66
+ opts = true
67
+ end
68
+
69
+ if tokens[1 + i] != nil && tokens[1 + i]["type"] == "OPTIONS"
70
+ if opts || props
71
+ raise SyntaxError.new "Cant have type OPTIONS here, must be PARAMS"
72
+ end
73
+ opts = true
74
+ altOpts = true
75
+ tmp += 1
76
+ end
77
+
78
+ ast_node = {"action" => tokens[0 + i]["value"]}
79
+
80
+ if props
81
+ ast_node["parameters"] = tokens[1 + i]["value"]
82
+ end
83
+
84
+ if opts
85
+ if altOpts
86
+ ast_node["options"] = tokens[1 + i]["value"]
87
+ else
88
+ ast_node["options"] = tokens[2 + i]["value"]
89
+ end
90
+ end
91
+
92
+ if !is_action? ast_node["action"]
93
+ throw SyntaxError.new "#{ast_node["action"]} is not a valid action!"
94
+ end
95
+
96
+ lacking = Array.new
97
+ lacking = get_args(ast_node["action"])
98
+
99
+ if props
100
+ ast_node["parameters"].each do |prop|
101
+ if !lacking.include? prop["key"]
102
+ raise SyntaxError.new "#{prop["key"]} is is already defined or is not a valid parameter for #{ast_node["action"]}!"
103
+ end
104
+ lacking.delete prop["key"]
105
+ end
106
+ else
107
+ ast_node["parameters"] = Array.new
108
+ end
109
+
110
+ ast_node["lacking_params"] = lacking
111
+
112
+ ast.append(ast_node)
113
+
114
+ i += tmp + 1 # + 1 for the keyword itself
115
+ end
116
+
117
+ ast
118
+ end
119
+ end
@@ -0,0 +1,73 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ require 'magister'
5
+
6
+ def zulu_to_ams(string)
7
+ ("%02d" % (string[0..1].to_i + 1)).to_s + string[2..-1]
8
+ end
9
+
10
+ module Runners
11
+ def login(username, password, school)
12
+ $magcli_runtime_variables["magister"].login(school, username, password)
13
+ end
14
+
15
+ def auth(token, school)
16
+ $magcli_runtime_variables["magister"].authenticate(school, token)
17
+ end
18
+
19
+ def get_classes(date_from, date_to)
20
+ classes = $magcli_runtime_variables["magister"].get_classes(date_from, date_to)
21
+ if classes == nil
22
+ raise "Couldn't fetch classes!"
23
+ end
24
+ if @opts["outputMode"]
25
+ classes.each do |c|
26
+ puts "|#{zulu_to_ams c.classStart.to_s[11..-13]} - #{zulu_to_ams c.classEndInclusive.to_s[11..-13]}| #{c.description} [#{c.location}]"
27
+ end
28
+ else
29
+ puts classes.to_json
30
+ end
31
+ end
32
+ end
33
+
34
+ class Runtime
35
+ include Runners
36
+
37
+ @@spec = {
38
+ "login" => :login,
39
+ "auth" => :auth,
40
+ "quit" => :exit,
41
+ "exit" => :exit,
42
+ "get_classes" => :get_classes
43
+ }
44
+ def initialize(action)
45
+ if action["options"] != nil
46
+ @opts = action["options"]
47
+ else
48
+ @opts = {"outputMode" => "formatted"}
49
+ end
50
+
51
+ if @opts["noCache"] != nil && @opts["noCache"] == "true"
52
+ $magister_useCache = false
53
+ else
54
+ $magister_useCache = true
55
+ end
56
+
57
+ requiredArgs = Parser.new("").get_args(action["action"])
58
+ args = Array.new
59
+
60
+ if action["parameters"] == nil
61
+ raise "Not a single parameter defined!! not even an empty array!"
62
+ end
63
+
64
+ requiredArgs.each do |arg|
65
+ action["parameters"].each do |param|
66
+ if arg == param["key"]
67
+ args.append(param["value"])
68
+ end
69
+ end
70
+ end
71
+ send(@@spec[action["action"]], *args)
72
+ end
73
+ end
@@ -0,0 +1,86 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+
5
+ class Tokenizer
6
+ @@spec = [
7
+ [/(\w+)/, "KEYWORD"],
8
+ [/(?:\w+\s?){(.*)}/, "PARAMS"],
9
+ [/(?:\w+\s?(?:{.*}\s?)?)\[(.*)\]/, "OPTIONS"],
10
+ [/(\s+)/, "EMPTY"]
11
+ ]
12
+
13
+ def initialize(string)
14
+ @string = string
15
+ end
16
+
17
+ def parse_options(optionsString)
18
+ cursor = 0
19
+ found = Array.new
20
+ while cursor < optionsString.length
21
+ scope = optionsString[cursor..-1]
22
+
23
+ if scope[0] == "{" || scope[0] == "}" || scope[0] == "[" || scope[0] == "]"
24
+ cursor += 1
25
+ next
26
+ end
27
+
28
+ whiteSpaceMatch = scope.match /^\s+/
29
+ if whiteSpaceMatch != nil
30
+ cursor += whiteSpaceMatch[0].length
31
+ next
32
+ end
33
+
34
+ keywordMatch = scope.match /^\w+\s?:/
35
+ if keywordMatch != nil
36
+ cursor += keywordMatch[0].length
37
+ found.append({"type" => "KEYWORD", "value" => keywordMatch[0][0..-2]})
38
+ next
39
+ end
40
+
41
+ explicitString = scope.match /^'([^']*)',*/
42
+ if explicitString != nil
43
+ cursor += explicitString[0].length
44
+ found.append({"type" => "STRING", "value" => explicitString.captures[0]})
45
+ next
46
+ end
47
+
48
+ impliedString = scope.match /^(.*?),*/
49
+ if impliedString != nil
50
+ cursor += impliedString[0].length
51
+ found.append({"type" => "STRING", "value" => impliedString.captures[0]})
52
+ next
53
+ end
54
+ end
55
+ parsed = Array.new
56
+ i = 0
57
+ while i < found.length
58
+ if found[i]["type"] != "KEYWORD" || found[i + 1]["type"] != "STRING"
59
+ raise TypeError.new "Expected #{found[i]["value"]} to be a KEYWORD and #{found[i + 1]["value"]} to be a STRING"
60
+ end
61
+
62
+ parsed.append({"type" => "PROPERTY", "key" => found[i]["value"], "value" => found[i + 1]["value"]})
63
+
64
+ i += 2
65
+ end
66
+ parsed
67
+ end
68
+
69
+ def tokenize
70
+ @tokens = Array.new
71
+ @@spec.each do |item|
72
+ matched = @string.match item[0]
73
+ if matched != nil
74
+ matched.captures.each do |match|
75
+ if item[1] == "PARAMS" || item[1] == "OPTIONS"
76
+ @tokens.append({"type" => item[1], "value" => parse_options(match)})
77
+ elsif item[1] == "EMPTY"
78
+ else
79
+ @tokens.append({"type" => item[1], "value" => match})
80
+ end
81
+ end
82
+ end
83
+ end
84
+ @tokens
85
+ end
86
+ end
data/lib/magister_cli.rb CHANGED
@@ -2,13 +2,24 @@
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  require 'magister'
5
+ require 'magister_cli/ext/string'
6
+ require 'magister_cli/parser'
7
+ require 'magister_cli/tokenizer'
8
+ require 'magister_cli/runtime'
9
+ require 'io/console'
10
+
11
+ $magister_cachingDirectory = Dir.home + "/.cache/magister"
5
12
 
6
13
  $magcli_runmode = "normal"
14
+ $magcli_runtime_variables = {}
7
15
 
8
16
  module MagisterCLI
9
17
  extend self
10
18
 
11
19
  def main
20
+ $magcli_runtime_variables["magister"] = Magister.new
21
+
22
+ begin
12
23
  if ARGV.include?("-r") || ARGV.include?("--run")
13
24
  $magcli_runmode = "inline"
14
25
  args = ARGV
@@ -27,9 +38,53 @@ module MagisterCLI
27
38
  return
28
39
  end
29
40
 
30
- # TODO: ask for command
31
- # TOOD: tokenize command
32
- # TODO: parse command
33
- # TODO: run command
41
+ parser = Parser.new("")
42
+ while true
43
+ print "> "
44
+ input = gets.chomp
45
+ parser.string = input
46
+ output = parser.parse
47
+
48
+ # loop over each action that was outputted
49
+ output.each do |action|
50
+ props = action["parameters"]
51
+ doneParams = Array.new
52
+ # get any parametres that werent set and ask then set them
53
+ action["lacking_params"].each do |param|
54
+ print "#{param}: "
55
+ if param == "password"
56
+ ans = STDIN.noecho(&:gets).chomp
57
+ print "\n"
58
+ else
59
+ ans = gets.chomp
60
+ end
61
+ props.append({"type" => "PROPERTY", "key" => param, "value" => ans})
62
+ doneParams.append param
63
+ end
64
+
65
+ # update lacking_params value, done here as to not mess with the order while looping over them
66
+ doneParams.each do |p|
67
+ action["lacking_params"].delete(p)
68
+ end
69
+ action["parameters"] = props
70
+ props = Array.new
71
+
72
+ runtime = Runtime.new(action)
73
+ end
74
+ end
75
+ rescue SignalException
76
+ $magcli_runtime_variables = Array.new
77
+ puts "[CTRL + C]\nExiting..."
78
+ exit
79
+ rescue UncaughtThrowError => e
80
+ if e.message.include? "#<SyntaxError: "
81
+ message = e.message.split("#<SyntaxError: ").last[0..-2]
82
+ puts "Invalid syntax: #{message}"
83
+ else
84
+ puts "Something went wrong: #{e.message}"
85
+ end
86
+ rescue => e
87
+ puts "Something went wrong: #{e.message}"
88
+ end
34
89
  end
35
90
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magister_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Riley0122
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-27 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2024-12-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description: The CLI for the 'magister' gem
14
28
  email: contact@riley0122.dev
15
29
  executables:
@@ -19,11 +33,15 @@ extra_rdoc_files: []
19
33
  files:
20
34
  - bin/magister
21
35
  - lib/magister_cli.rb
22
- homepage: https://github.com/riley0122/rubymag/cli#readme
36
+ - lib/magister_cli/ext/string.rb
37
+ - lib/magister_cli/parser.rb
38
+ - lib/magister_cli/runtime.rb
39
+ - lib/magister_cli/tokenizer.rb
40
+ homepage: https://github.com/riley0122/rubymag/tree/main/cli#readme
23
41
  licenses:
24
42
  - MPL-2.0
25
43
  metadata:
26
- source_code_uri: https://github.com/riley0122/rubymag/cli
44
+ source_code_uri: https://github.com/riley0122/rubymag/tree/main/cli
27
45
  post_install_message:
28
46
  rdoc_options: []
29
47
  require_paths: