Неграмотный OCaml нуждается в помощи при обработке записей

#ocaml #command-line-arguments #record

#ocaml #аргументы командной строки #запись

Вопрос:

Это немного смущает, но мне показали программу OCaml, в которой я знаю, что хочу делать, но я не могу найти документацию, которая помогла бы мне написать то, что я хочу, в правильном синтаксисе, поскольку я никогда раньше не использовал этот язык.

Я внес довольно много рабочих изменений в программу, и это последнее изменение, которое мне нужно внести, и я не могу его обработать!

Существует запись определенного типа (используемый синтаксис меня сбил с толку) с именем caps_default :

 let caps_default =
    {
        browserName = Firefox ;
        version = "" ;
        platform = ANY ;
        username = "" ;
        accessKey = "" ;
        javascriptEnabled = true
    }
;;
  

Затем эти переменные определяются для получения аргументов командной строки:

 exception Incorrect_cmdline of string option
;;

let browser_name   = ref ""
and hub_url_opt    = ref ""
and target_url_opt = ref ""
and xml_out_string = ref ""
and user_name      = ref ""
and access_key     = ref ""
;;
  

Я добавил два новых аргумента с именами ‘username’ и ‘accessKey’, и я хочу добавить их в запись «caps».

Продолжая, здесь анализируются аргументы командной строки:

 let (target_url, hub_url, caps, xml_out) =
    try
        parse_cmdline
            [
                ( noshort , "browser-name" , None, (atmost_once browser_name   (Incorrect_cmdline (Some "browser-name"))) ) ;
                ( noshort , "hub-url"      , None, (atmost_once hub_url_opt    (Incorrect_cmdline (Some "hub-url"))) ) ;
                ( noshort , "target-url"   , None, (atmost_once target_url_opt (Incorrect_cmdline (Some "target-url"))) ) ;
                ( noshort , "xml-output"   , None, (atmost_once xml_out_string (Incorrect_cmdline (Some "xml-output"))) ) ;
                ( noshort , "username"     , None, (atmost_once user_name      (Incorrect_cmdline (Some "username"))) ) ;
                ( noshort , "accessKey"    , None, (atmost_once access_key     (Incorrect_cmdline (Some "accessKey"))) ) ;
                ( noshort , "help"         , Some (fun s -> raise (Incorrect_cmdline None)) , None );
            ]
            ( fun x -> raise (Incorrect_cmdline None)) ;
        ignore (List.map
                (fun s -> if BatString.is_empty !s then raise (Incorrect_cmdline None) else () )
                [ browser_name ; hub_url_opt ; target_url_opt ] );
        let target_url =
            try
            Neturl.parse_url !target_url_opt
            with
            Neturl.Malformed_URL ->
            raise (Incorrect_cmdline (Some ("Invalid target url: " ^ !target_url_opt)))
        and hub_url =
            try
            Neturl.parse_url !hub_url_opt
            with
            Neturl.Malformed_URL ->
            raise (Incorrect_cmdline (Some ("Invalid hub url: " ^ !hub_url_opt)))
        and xml_out =
            if BatString.is_empty !xml_out_string
            then fun s -> ignore s
            else
            let chan = open_out !xml_out_string in
            (fun xml ->
            output_string chan (Xml.to_string xml) ;
            close_out chan )
        (* Continued below *)
  

Я хочу использовать мои новые параметры аргумента командной строки username и accessKey , присвоенные переменным user_name и access_key , для передачи в caps запись, которая определена в назначениях let ниже:

         (* Continued from above *)
        and caps =
            { caps_default with username = !user_name }   (* My addition *)
            { caps_default with accessKey = !access_key } (* My addition *)
            match !browser_name with   (* This switch is original and worked *)
            | "firefox"   -> { caps_default with browserName = Firefox }
            | "chrome"    -> { caps_default with browserName = Chrome }
            | "html_unit" -> { caps_default with browserName = HtmlUnit }
            | "ie"        -> { caps_default with browserName = InternetExplorer }
            | "iphone"    -> { caps_default with browserName = IPhone }
            |  _        -> raise (Incorrect_cmdline (Some ("Invalid browser name: " ^ !browser_name)))
        in
        (target_url, hub_url, caps, xml_out)
    with
        Incorrect_cmdline arg ->
            (match arg with | None -> () | Some msg -> print_endline msg) ;
            print_synopsis () ;
            exit 48
;; (* End of relevant code *)
  

Experimenting I could comment out the original author’s switch for —browser-name and assign a single value by putting a solemn line surrounded by curly braces:

 and caps=
    { caps_default with browserName = Chrome } (* Hard-coding a Chrome choice *)
  

or

 and caps=
    { caps_default with username = !user_name } (* Sharing only --username *)
  

or

 and caps=
    { caps_default with accessKey = !access_key } (* Sharing only --accessKey *)
  

Can someone point me in the correct direction? I want to keep the switch the original author wrote but also transmit the username and accessKey strings to the caps record on top of that. Can I change the caps object later? Can I modify default_caps beforehand and then copy it to caps ?

This code is only run once per execution, so modifying the default_caps object is of absolutely no concern, even if it’s not very kosher to do so.

Thanks for any assistance!

Update

Numerous thanks to Dr. Scofield’s assistance so far. Curiously I am now being met with a slightly different error complaining about what I can only assume is a mis-match of type. Here is the content of the error:

 File "tester.ml", line 110, characters 40-47:
Error: This expression has type Selenium.Json_client.capabilities
       but an expression was expected of type Selenium.Json_client.browser
  

Строка 110

 { caps_default with browserName = browser;
  

в фрагменте кода мистера Скофилда 40-47 browser .

Определение типа default_caps ‘s capabilities как таковое:

 type capabilities =
  {
    browserName       : browser  ;
    version           : string   ;
    platform          : platform ;
    javascriptEnabled : bool     ;
    username          : string   ;
    accessKey         : string   ;
  }
  

И аналогично, тип browser :

 type browser =
  Chrome | Firefox | HtmlUnit | InternetExplorer | IPhone
  

mli (интерфейс, правильно?) определения идентичны, если это важно.

Обновление, часть 2

Небольшая коррекция необходима только для упрощения кода из этого:

 match !browser_name with
| "firefox"   -> { caps_default with browserName = Firefox }
| "chrome"    -> { caps_default with browserName = Chrome }
| "html_unit" -> { caps_default with browserName = HtmlUnit }
| "ie"        -> { caps_default with browserName = InternetExplorer }
| "iphone"    -> { caps_default with browserName = IPhone }
|  _        -> raise (Incorrect_cmdline (Some ("Invalid browser name: " ^ !browser_name)))
  

к этому:

 match !browser_name with
| "firefox"   -> Firefox
| "chrome"    -> Chrome
| "html_unit" -> HtmlUnit
| "ie"        -> InternetExplorer
| "iphone"    -> IPhone
|  _        -> raise (Incorrect_cmdline (Some ("Invalid browser name: " ^ !browser_name)))
  

Прежде чем продолжить:

 in
{ caps_default with browserName = browser;
                    username    = !user_name;
                    accessKey   = !access_key;
}
  

Ответ №1:

Возможно, вам придется изучить немного больше OCaml, чем вы хотите, чтобы сделать это 🙂

Названный объект caps_default является записью, то есть он имеет тип записи. Вам нужно будет найти определение этого типа записи и добавить к нему свои новые возможности.

Обновить

Хорошо, у вас уже был исправлен тип записи. Вот некоторый код

     and caps =
        let browser = 
            match !browser_name with
            | "firefox"   ->  Firefox
            | "chrome"    ->  Chrome
            | "html_unit" ->  HtmlUnit
            | "ie"        ->  InternetExplorer
            | "iphone"    ->  IPhone
            |  _        ->
                raise (Incorrect_cmdline
                   (Some ("Invalid browser name: " ^ !browser_name)))
        in
        { caps_default with browserName = browser;
                            username = !user_name;
                            accessKey = !access_key;
        }
    in
    (target_url, hub_url, caps, xml_out)
  

(Излишне говорить, что это непроверенный код.)

Обновление 2

(Исправлено написание user_name , спасибо.)

Комментарии:

1. Ах, я подозревал, что это запись, я уже это сделал, и, к счастью, я дал им оба строковых типа. Увы, я все еще не понимаю, как правильно назначить полученные аргументы командной строки caps и поддерживать существующий коммутатор.

2. Пока это отличная помощь. Но, что любопытно, я столкнулся с еще одной проблемой, связанной с неправильным соответствием типов. Я обновил исходный вопрос новой частью в конце.

3. В моем исходном коде были ошибки. Посмотрите на приведенный выше код еще раз. (Извините.)

4. А-ха! Да, я вижу, где что-то пошло не так. Большое вам спасибо, мистер Скофилд, похоже, это отлично подходит для моих нужд. Я бы проголосовал за ваш ответ, но, видимо, мне нужно еще 2 представителя, чтобы сделать это, хах. PS: Еще одно крошечное исправление — это !username когда оно должно быть !user_name для всех, кто может увидеть это позже в качестве руководства.