نواصل الحديث عن Elm 0.18 .
الدردار. مريح ومحرج
الدردار. مريح ومحرج. تكوين
الدردار. مريح ومحرج. Http ، المهمة
تتناول هذه المقالة مشكلات برامج التشفير / أجهزة فك التشفير.
تستخدم أجهزة التشفير / التشفير في:
- تحويل الاستجابات من موارد الطرف الثالث (Http ، WebSocket ، إلخ) ؛
- التفاعلات عبر الموانئ. سأخبرك المزيد عن الموانئ والرمز الأصلي في المقالات التالية.
كما هو موضح سابقًا ، يتطلب منا Elm تحويل البيانات الخارجية إلى أنواع تطبيقات داخلية. الوحدة النمطية Json.Decode هي المسؤولة عن هذه العملية. العملية العكسية هي Json.Encode .
النوع الذي يحدد قواعد فك التشفير هو Json.Decode.Decoder a . يتم تحديد هذا النوع بواسطة نوع المستخدم ويحدد كيفية الحصول على نوع المستخدم من كائن JSON.
بالنسبة إلى برنامج التشفير ، يتم تحديد نوع النتيجة فقط - Json.Encode.Value .
خذ بعين الاعتبار أمثلة لنوع UserData.
type alias User = { id: Int , name: String , email: String }
مفكك الشفرة لاستقبال البيانات من المستخدم:
decodeUserData : Json.Decode.Decoder UserData decodeUserData = Json.Decode.map3 UserData (Json.Decode.field “id” Json.Decode.int) (Json.Decode.field “name” Json.Decode.string) (Json.Decode.field “email” Json.Decode.string) encodeUserData : UserData -> Json.Encode.Value encodeUserData userData = Json.Encode.object [ ( “id”, Json.Encode.int userData.id) , ( “name”, Json.Encode.string userData.name) , ( “email”, Json.Encode.string userData.email) ]
تقبل الدالة Json.Decode.map3 مُنشئ من نوع UserData. بعد ذلك ، يتم إرسال ثلاثة أجهزة فك تشفير من النوع وفقًا لترتيب الإعلان عنها في نوع المستخدم UserData.
يمكن استخدام الدالة decodeUserData بالتزامن مع دالات Json.Decode.decodeString أو Json.Decode.decodeValue. مثال للاستخدام من المقالات السابقة.
تنتج الدالة encodeUserData ترميز نوع مخصص لنوع Json.Encode.Value ، والذي يمكن إرساله. بعبارات بسيطة ، يتوافق Json.Encode.Value مع كائن JSON.
يتم وصف الخيارات البسيطة في الوثائق ، ويمكن دراستها دون صعوبة كبيرة. دعونا نلقي نظرة على حالات الحياة التي تتطلب بعض خفة اليد.
نوع أجهزة فك التشفير أو نوع التمييز
لنفترض أن لدينا كتالوج للسلع. ويمكن أن يكون لكل منتج عدد عشوائي من السمات ، لكل منها نوع من العديد من السمات:
- عدد صحيح
- سلسلة
- تعداد. يفترض اختيار إحدى القيم الصالحة.
كائن JSON صالح على النحو التالي:
{ “id”: 1, “name”: “Product name”, “price”: 1000, “attributes”: [ { “id”: 1, “name”: “Length”, “unit”: “meters”, “value”: 100 }, { “id”: 1, “name”: “Color”, “unit”: “”, “value”: { “id”: 1, “label”: “red” } },... ] }
لن يتم النظر في الأنواع المحتملة المتبقية ؛ فالعمل معهم مشابه. ثم سيكون نوع المنتج المخصص الوصف التالي:
type alias Product = { id: Int , name: String , price: Int , attributes: Attributes } type alias Attributes = List Attribute type alias Attribute = { id: Int , name: String , unit: String , value: AttributeValue } type AttributeValue = IntValue Int | StringValue String | EnumValue Enum type alias Enum = { id: Int , label: String }
سنناقش قليلا الأنواع الموصوفة. يوجد منتج (منتج) يحتوي على قائمة بالسمات / الخصائص (السمات). تحتوي كل سمة (سمة) على معرف واسم وبُعد وقيمة. يتم وصف قيمة السمة كنوع اتحاد ، وهو عنصر واحد لكل نوع من القيم المميزة. يصف نوع التعداد قيمة واحدة من مجموعة مقبولة ويحتوي على: المعرف وقيمة قابلة للقراءة البشرية.
وصف وحدة فك الترميز ، احذف بادئة Json.Decode للإيجاز:
decodeProduct : Decoder Product decodeProduct = map4 Product (field “id” int) (field “name” string) (field “price” int) (field “attributes” decodeAttributes) decodeAttributes : Decoder Attributes decodeAttributes = list decodeAttribute decodeAttribute : Decoder Attribute decodeAttribute = map4 Attribute (field “id” int) (field “name” string) (field “unit” string) (field “value” decodeAttributeValue) decodeAttributeValue : Decoder AttributeValue decodeAttributeValue = oneOf [ map IntValue int , map StringValue string , map EnumValue decodeEnumValue ] decodeEnumValue : Decoder Enum decodeEnumValue = map2 Enum (field “id” int) (field “label” string)
الحيلة بأكملها موجودة في دالة decodeAttributeValue. يؤدي استخدام وظيفة Json.Decode.oneOf إلى التكرار عبر جميع أجهزة فك التشفير الصالحة لقيمة السمة. في حالة تفريغ أحد أجهزة فك التشفير بنجاح ، يتم تمييز القيمة بالعلامة المقابلة من نوع AttributeValue.
يمكن تنفيذ ترميز نوع المنتج باستخدام وظيفة Json.Encode.object ، حيث سيتم تمرير سمات النوع المشفر. يجدر الانتباه إلى ترميز نوع AttributeValue. وفقًا لكائن JSON الموصوف سابقًا ، يمكن وصف برنامج التشفير بأنه ، يتم حذف بادئة Json.Encode للإيجاز:
encodeAttributeValue : AttributeValue -> Value encodeAttributeValue attributeValue = case attributeValue of IntValue value -> int value StringValue value -> string value EnumValue value -> object [ (“id”, int value.id) , (“id”, string value.label) ]
كما ترى ، نقارن خيارات الكتابة ونستخدم برامج التشفير المقابلة.
قم بتغيير وصف السمات وتعريفها باستخدام نوع التمييز. في هذه الحالة ، سيبدو كائن سمة JSON كما يلي:
{ “id”: 1, “name”: “Attribute name”, “type”: “int”, “value_int”: 1, “value_string”: null, “value_enum_id”: null, “value_enum_label”: null }
في هذه الحالة ، يتم تخزين تمييز النوع في حقل النوع ويحدد في أي حقل يتم تخزين القيمة. ربما لا يكون هيكل الوصف هذا هو الأكثر ملاءمة ، ولكن غالبًا ما يوجد. ربما لا يستحق تغيير وصف النوع لكائن JSON هذا ، فمن الأفضل الاحتفاظ بالأنواع في شكل مناسب للاستخدام الداخلي. في هذه الحالة ، قد يكون وصف مفكك الشفرة كما يلي:
decodeAttribute2 : Decoder Attribute decodeAttribute2 = field "type" string |> andThen decodeAttributeValueType |> andThen (\attributeValue -> map4 Attribute (field "id" int) (field "name" string) (field "unit" string) (succeed attributeValue) ) decodeAttributeValueType : String -> Decoder AttributeValue decodeAttributeValueType valueType = case valueType of "int" -> field "value_int" int |> Json.Decode.map IntValue "string" -> field "value_string" string |> Json.Decode.map StringValue "enum" -> map2 Enum (field "value_enum_id" int) (field "value_enum_label" string) |> Json.Decode.map EnumValue _ -> Json.Decode.fail "Unknown attribute type"
في دالة decodeAttribute2 ، نقوم أولاً بفك تشفير المميّز ، إذا نجح ، فإننا نفك شفرة قيمة السمة. بعد ذلك ، نقوم بفك ترميز الحقول المتبقية من نوع السمة ، ونشير إلى القيمة التي تم الحصول عليها مسبقًا كقيمة حقل القيمة.
كود مصدر وحدة فك الترميز .
تحديث النوع الجزئي
هناك حالات لا تقوم فيها واجهة برمجة التطبيقات بإرجاع الكائن بالكامل ، ولكن جزءًا منه فقط. على سبيل المثال ، عند التسجيل لعرض أو تغيير حالة كائن. في هذه الحالة ، من الأسهل استقبال الكائن المحدث في الرسالة على الفور ، وإخفاء كل التلاعبات وراء وحدة فك الترميز.
على سبيل المثال ، نأخذ نفس المنتج ، ولكن نضيف حقل الحالة إليه وسنقوم بمعالجة طلب إغلاق المنتج.
type alias Product = { id: Int , name: String , price: Int , attributes: Attributes , status: Int } decodeUpdateStatus : Product -> Decoder Product decodeUpdateStatus product = field “status” int |> andThen (\newStatus -> succeed { product | status = newStatus} )
أو يمكنك استخدام وظيفة Json.Decode.map.
decodeUpdateStatus : Product -> Decoder Product decodeUpdateStatus product = field “status” int |> map (\newStatus -> { product | status = newStatus} )
التاريخ والوقت
سنستخدم الدالة Date.fromString ، التي يتم تنفيذها باستخدام مُنشئ نوع التاريخ.
decodeDateFromString : Decoder Date.Date decodeDateFromString = string |> andThen (\stringDate -> case Date.fromString stringDate of Ok date -> Json.Decode.succeed date Err reason -> Json.Decode.fail reason )
إذا تم استخدام الطابع الزمني لتمثيل التاريخ / الوقت ، فيمكن حينئذٍ وصف مفكك التشفير على النحو التالي:
decodeDateFromTimestamp : Decoder Date.Date decodeDateFromTimestamp = oneOf [ int |> Json.Decode.map toFloat , float ] |> Json.Decode.map Date.fromTime