magister_cli 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c679885476aafdf7a4ac673994d31396be72982161a554aebd78ed66b13814ab
4
- data.tar.gz: d762dad23dcfb491ef7295241f663f6da9b310bf441e92f3db7a73043e12c5ce
3
+ metadata.gz: fc4e88673fb16d2fa82e0e23bd3312a684584a7eea909d101c49c7e96dd0c3c1
4
+ data.tar.gz: ffbb5497cc609cbdb4d775fdb92160f9d6ad559955cde2644c451f687795a005
5
5
  SHA512:
6
- metadata.gz: 89799db254ad526cfc7f05370809aa3923d83d9e1aca5f57d3061d18a11ed18f9472b6d5c9c8f32d54a063f68578a6b4dcd1d599189507f45f84658203a74395
7
- data.tar.gz: bbb0d7a439c9d2d37d64222dfaa7eed37fbe92c00a621bb18a069bde8e652971e1d71a392753d5445b481c8424f2e37ed210be42b81314098cfbc190d052bd0e
6
+ metadata.gz: 489fb98b433f60be95f0c444a8006dc014f677798b489d4341debd299c63d77d21fde38cc5805bffb3e3d45ab4fefcfb06cccf5decb34fecbe0c0de8bdcb5614
7
+ data.tar.gz: bd1e443124ecb18d1906fdd0ac7aa9c0db6e51c2bb7e309347b99f02ebbece9d01d4f66a92a8f9441b2c90fd58f3897c354501df4185f3338a9415317ff73c35
@@ -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,43 @@
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.0
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-02-29 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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: magister
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  description: The CLI for the 'magister' gem
14
42
  email: contact@riley0122.dev
15
43
  executables:
@@ -19,11 +47,15 @@ extra_rdoc_files: []
19
47
  files:
20
48
  - bin/magister
21
49
  - lib/magister_cli.rb
22
- homepage: https://github.com/riley0122/rubymag/cli#readme
50
+ - lib/magister_cli/ext/string.rb
51
+ - lib/magister_cli/parser.rb
52
+ - lib/magister_cli/runtime.rb
53
+ - lib/magister_cli/tokenizer.rb
54
+ homepage: https://github.com/riley0122/rubymag/tree/main/cli#readme
23
55
  licenses:
24
56
  - MPL-2.0
25
57
  metadata:
26
- source_code_uri: https://github.com/riley0122/rubymag/cli
58
+ source_code_uri: https://github.com/riley0122/rubymag/tree/main/cli
27
59
  post_install_message:
28
60
  rdoc_options: []
29
61
  require_paths: